From 68c2f11240c55992b8d56a22f25641cf6abd9f08 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 10 Jan 2024 16:30:07 +0000 Subject: [PATCH 1/9] Remove special-casing around aliaskind in new solver --- compiler/rustc_hir_analysis/src/autoderef.rs | 2 +- .../src/solve/normalize.rs | 41 ++++++++------- .../src/traits/structural_normalize.rs | 3 +- tests/ui/coroutine/clone-rpit.next.stderr | 52 +++++++++++++++++++ tests/ui/coroutine/clone-rpit.rs | 3 +- .../eagerly-reveal-in-local-body.rs | 13 +++++ ...ecursive-coroutine-indirect.current.stderr | 2 +- .../recursive-coroutine-indirect.next.stderr | 2 +- .../recursive-coroutine-indirect.rs | 4 ++ .../opaque-type-unsatisfied-bound.rs | 9 ++-- .../opaque-type-unsatisfied-bound.stderr | 41 ++------------- .../opaque-type-unsatisfied-fn-bound.rs | 3 +- .../opaque-type-unsatisfied-fn-bound.stderr | 16 +----- .../traits/next-solver/alias-bound-unsound.rs | 6 +-- .../next-solver/alias-bound-unsound.stderr | 3 +- .../recursive-self-normalization-2.rs | 6 ++- .../recursive-self-normalization-2.stderr | 21 +++++++- .../overflow/recursive-self-normalization.rs | 6 ++- .../recursive-self-normalization.stderr | 21 +++++++- 19 files changed, 158 insertions(+), 96 deletions(-) create mode 100644 tests/ui/coroutine/clone-rpit.next.stderr create mode 100644 tests/ui/impl-trait/eagerly-reveal-in-local-body.rs diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 5f5994879126b..556560945e94f 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // we have some type like `&::Assoc`, since users of // autoderef expect this type to have been structurally normalized. if self.infcx.next_trait_solver() - && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind() + && let ty::Alias(..) = ty.kind() { let (normalized_ty, obligations) = self.structurally_normalize(ty)?; self.state.obligations.extend(obligations); diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 55b79e6fc3968..d87cc89954a56 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::{ObligationCause, Reveal}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; @@ -52,14 +52,16 @@ struct NormalizationFolder<'me, 'tcx> { impl<'tcx> NormalizationFolder<'_, 'tcx> { fn normalize_alias_ty( &mut self, - alias: AliasTy<'tcx>, + alias_ty: Ty<'tcx>, ) -> Result, Vec>> { + assert!(matches!(alias_ty.kind(), ty::Alias(..))); + let infcx = self.at.infcx; let tcx = infcx.tcx; let recursion_limit = tcx.recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.at.infcx.err_ctxt().report_overflow_error( - &alias.to_ty(tcx), + &alias_ty, self.at.cause.span, true, |_| {}, @@ -76,7 +78,11 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { tcx, self.at.cause.clone(), self.at.param_env, - ty::NormalizesTo { alias, term: new_infer_ty.into() }, + ty::PredicateKind::AliasRelate( + alias_ty.into(), + new_infer_ty.into(), + ty::AliasRelationDirection::Equate, + ), ); // Do not emit an error if normalization is known to fail but instead @@ -90,9 +96,12 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { return Err(errors); } let ty = infcx.resolve_vars_if_possible(new_infer_ty); - ty.try_fold_with(self)? + + // Alias is guaranteed to be fully structurally resolved, + // so we can super fold here. + ty.try_super_fold_with(self)? } else { - alias.to_ty(tcx).try_super_fold_with(self)? + alias_ty.try_super_fold_with(self)? }; self.depth -= 1; @@ -170,24 +179,18 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { } fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { - let reveal = self.at.param_env.reveal(); let infcx = self.at.infcx; debug_assert_eq!(ty, infcx.shallow_resolve(ty)); - if !needs_normalization(&ty, reveal) { + if !ty.has_projections() { return Ok(ty); } - // We don't normalize opaque types unless we have - // `Reveal::All`, even if we're in the defining scope. - let data = match *ty.kind() { - ty::Alias(kind, alias_ty) if kind != ty::Opaque || reveal == Reveal::All => alias_ty, - _ => return ty.try_super_fold_with(self), - }; + let ty::Alias(..) = *ty.kind() else { return ty.try_super_fold_with(self) }; - if data.has_escaping_bound_vars() { - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let result = ensure_sufficient_stack(|| self.normalize_alias_ty(data))?; + if ty.has_escaping_bound_vars() { + let (ty, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); + let result = ensure_sufficient_stack(|| self.normalize_alias_ty(ty))?; Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -197,7 +200,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { result, )) } else { - ensure_sufficient_stack(|| self.normalize_alias_ty(data)) + ensure_sufficient_stack(|| self.normalize_alias_ty(ty)) } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index e0f9fdc3827fb..ed5d01d7048e6 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -22,8 +22,7 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { - // FIXME(-Znext-solver): Should we resolve opaques here? - let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = *ty.kind() else { + let ty::Alias(..) = *ty.kind() else { return Ok(ty); }; diff --git a/tests/ui/coroutine/clone-rpit.next.stderr b/tests/ui/coroutine/clone-rpit.next.stderr new file mode 100644 index 0000000000000..2dbdbcc7b055d --- /dev/null +++ b/tests/ui/coroutine/clone-rpit.next.stderr @@ -0,0 +1,52 @@ +error[E0391]: cycle detected when type-checking `foo` + --> $DIR/clone-rpit.rs:12:1 + | +LL | pub fn foo<'a, 'b>() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires coroutine witness types for `foo::{closure#0}`... + --> $DIR/clone-rpit.rs:13:5 + | +LL | move |_: ()| { + | ^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `foo::{closure#0}`... + --> $DIR/clone-rpit.rs:13:5 + | +LL | move |_: ()| { + | ^^^^^^^^^^^^ +note: ...which requires preparing `foo::{closure#0}` for borrow checking... + --> $DIR/clone-rpit.rs:13:5 + | +LL | move |_: ()| { + | ^^^^^^^^^^^^ +note: ...which requires checking if `foo::{closure#0}` contains FFI-unwind calls... + --> $DIR/clone-rpit.rs:13:5 + | +LL | move |_: ()| { + | ^^^^^^^^^^^^ +note: ...which requires building MIR for `foo::{closure#0}`... + --> $DIR/clone-rpit.rs:13:5 + | +LL | move |_: ()| { + | ^^^^^^^^^^^^ +note: ...which requires match-checking `foo::{closure#0}`... + --> $DIR/clone-rpit.rs:13:5 + | +LL | move |_: ()| { + | ^^^^^^^^^^^^ +note: ...which requires type-checking `foo::{closure#0}`... + --> $DIR/clone-rpit.rs:13:5 + | +LL | move |_: ()| { + | ^^^^^^^^^^^^ + = note: ...which again requires type-checking `foo`, completing the cycle +note: cycle used when computing type of opaque `foo::{opaque#0}` + --> $DIR/clone-rpit.rs:12:25 + | +LL | pub fn foo<'a, 'b>() -> impl Clone { + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/coroutine/clone-rpit.rs b/tests/ui/coroutine/clone-rpit.rs index cbd28f88fcb83..22a553c83d636 100644 --- a/tests/ui/coroutine/clone-rpit.rs +++ b/tests/ui/coroutine/clone-rpit.rs @@ -1,6 +1,7 @@ // revisions: current next //[next] compile-flags: -Znext-solver -// check-pass +//[current] check-pass +//[next] known-bug: trait-system-refactor-initiative#82 #![feature(coroutines, coroutine_trait, coroutine_clone)] diff --git a/tests/ui/impl-trait/eagerly-reveal-in-local-body.rs b/tests/ui/impl-trait/eagerly-reveal-in-local-body.rs new file mode 100644 index 0000000000000..a08c2c8765ba6 --- /dev/null +++ b/tests/ui/impl-trait/eagerly-reveal-in-local-body.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait)] + +fn main() { + type Tait = impl Sized; + struct S { + i: i32, + } + let x: Tait = S { i: 0 }; + println!("{}", x.i); +} diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr index 11b3c4ef00784..df457c13e70cb 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in a coroutine requires boxing - --> $DIR/recursive-coroutine-indirect.rs:6:5 + --> $DIR/recursive-coroutine-indirect.rs:10:5 | LL | move || { | ^^^^^^^ diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr index 11b3c4ef00784..df457c13e70cb 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.next.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in a coroutine requires boxing - --> $DIR/recursive-coroutine-indirect.rs:6:5 + --> $DIR/recursive-coroutine-indirect.rs:10:5 | LL | move || { | ^^^^^^^ diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.rs b/tests/ui/impl-trait/recursive-coroutine-indirect.rs index 4f8d4d330505e..99b6be3358fc0 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.rs +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.rs @@ -1,5 +1,9 @@ // revisions: current next //[next] compile-flags: -Znext-solver + +//[next] build-fail +// Deeply normalizing writeback results of opaques makes this into a post-mono error :( + #![feature(coroutines)] #![allow(unconditional_recursion)] fn coroutine_hold() -> impl Sized { diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs index e1e93f7992065..01a98a308950a 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs @@ -13,11 +13,8 @@ fn main() { } fn weird0() -> impl Sized + !Sized {} -//~^ ERROR mismatched types -//~| ERROR type mismatch resolving `() == impl !Sized + Sized` +//~^ ERROR type mismatch resolving `() == impl !Sized + Sized` fn weird1() -> impl !Sized + Sized {} -//~^ ERROR mismatched types -//~| ERROR type mismatch resolving `() == impl !Sized + Sized` +//~^ ERROR type mismatch resolving `() == impl !Sized + Sized` fn weird2() -> impl !Sized {} -//~^ ERROR mismatched types -//~| ERROR type mismatch resolving `() == impl !Sized` +//~^ ERROR type mismatch resolving `() == impl !Sized` diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr index 627927618707f..d803e56e8170c 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr @@ -1,50 +1,17 @@ -error[E0308]: mismatched types - --> $DIR/opaque-type-unsatisfied-bound.rs:15:36 - | -LL | fn weird0() -> impl Sized + !Sized {} - | ------------------- ^^ types differ - | | - | the expected opaque type - | - = note: expected opaque type `impl !Sized + Sized` - found unit type `()` - error[E0271]: type mismatch resolving `() == impl !Sized + Sized` --> $DIR/opaque-type-unsatisfied-bound.rs:15:16 | LL | fn weird0() -> impl Sized + !Sized {} | ^^^^^^^^^^^^^^^^^^^ types differ -error[E0308]: mismatched types - --> $DIR/opaque-type-unsatisfied-bound.rs:18:36 - | -LL | fn weird1() -> impl !Sized + Sized {} - | ------------------- ^^ types differ - | | - | the expected opaque type - | - = note: expected opaque type `impl !Sized + Sized` - found unit type `()` - error[E0271]: type mismatch resolving `() == impl !Sized + Sized` - --> $DIR/opaque-type-unsatisfied-bound.rs:18:16 + --> $DIR/opaque-type-unsatisfied-bound.rs:17:16 | LL | fn weird1() -> impl !Sized + Sized {} | ^^^^^^^^^^^^^^^^^^^ types differ -error[E0308]: mismatched types - --> $DIR/opaque-type-unsatisfied-bound.rs:21:28 - | -LL | fn weird2() -> impl !Sized {} - | ----------- ^^ types differ - | | - | the expected opaque type - | - = note: expected opaque type `impl !Sized` - found unit type `()` - error[E0271]: type mismatch resolving `() == impl !Sized` - --> $DIR/opaque-type-unsatisfied-bound.rs:21:16 + --> $DIR/opaque-type-unsatisfied-bound.rs:19:16 | LL | fn weird2() -> impl !Sized {} | ^^^^^^^^^^^ types differ @@ -63,7 +30,7 @@ note: required by a bound in `consume` LL | fn consume(_: impl Trait) {} | ^^^^^ required by this bound in `consume` -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277, E0308. +Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs index 72bca1a8910b5..bb2e861a1a770 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs @@ -3,7 +3,6 @@ #![feature(negative_bounds, unboxed_closures)] fn produce() -> impl !Fn<(u32,)> {} -//~^ ERROR mismatched types -//~| ERROR type mismatch resolving `() == impl !Fn<(u32,)>` +//~^ ERROR type mismatch resolving `() == impl !Fn<(u32,)>` fn main() {} diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr index a4fb4b2b5c47f..1fd30410b0084 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr @@ -1,21 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:34 - | -LL | fn produce() -> impl !Fn<(u32,)> {} - | ---------------- ^^ types differ - | | - | the expected opaque type - | - = note: expected opaque type `impl !Fn<(u32,)>` - found unit type `()` - error[E0271]: type mismatch resolving `() == impl !Fn<(u32,)>` --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17 | LL | fn produce() -> impl !Fn<(u32,)> {} | ^^^^^^^^^^^^^^^^ types differ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0271, E0308. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.rs b/tests/ui/traits/next-solver/alias-bound-unsound.rs index 4e279a84a3356..8fddbd7ecdcc8 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/next-solver/alias-bound-unsound.rs @@ -23,10 +23,10 @@ fn main() { let x = String::from("hello, world"); drop(<() as Foo>::copy_me(&x)); //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized` - //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` - //~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed` //~| ERROR overflow evaluating the requirement `String <: <() as Foo>::Item` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed` //~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed` - //~| ERROR overflow evaluating the requirement `<() as Foo>::Item normalizes-to _` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` println!("{x}"); } diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.stderr b/tests/ui/traits/next-solver/alias-bound-unsound.stderr index ac3f19b3fe672..874644317ebd3 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/next-solver/alias-bound-unsound.stderr @@ -52,13 +52,14 @@ LL | drop(<() as Foo>::copy_me(&x)); | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) -error[E0275]: overflow evaluating the requirement `<() as Foo>::Item normalizes-to _` +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` --> $DIR/alias-bound-unsound.rs:24:10 | LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 7 previous errors diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs index 327ef865de9c6..71b1502d775fc 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -13,8 +13,10 @@ fn needs_bar() {} fn test::Assoc2> + Foo2::Assoc1>>() { needs_bar::(); - //~^ ERROR overflow evaluating the requirement `::Assoc1: Bar` - //~| ERROR overflow evaluating the requirement `::Assoc2` + //~^ ERROR overflow evaluating the requirement `::Assoc1 == _` + //~| ERROR overflow evaluating the requirement `::Assoc1 == _` + //~| ERROR overflow evaluating the requirement `::Assoc1 == _` + //~| ERROR overflow evaluating the requirement `::Assoc1: Bar` } fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr index eda62b99c4405..bad6820f7389d 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -11,7 +11,7 @@ note: required by a bound in `needs_bar` LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` -error[E0275]: overflow evaluating the requirement `::Assoc2` +error[E0275]: overflow evaluating the requirement `::Assoc1 == _` --> $DIR/recursive-self-normalization-2.rs:15:5 | LL | needs_bar::(); @@ -19,6 +19,23 @@ LL | needs_bar::(); | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) -error: aborting due to 2 previous errors +error[E0275]: overflow evaluating the requirement `::Assoc1 == _` + --> $DIR/recursive-self-normalization-2.rs:15:5 + | +LL | needs_bar::(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0275]: overflow evaluating the requirement `::Assoc1 == _` + --> $DIR/recursive-self-normalization-2.rs:15:17 + | +LL | needs_bar::(); + | ^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs index f45d208e6667f..809a6a59ca6aa 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs @@ -9,8 +9,10 @@ fn needs_bar() {} fn test::Assoc>>() { needs_bar::(); - //~^ ERROR overflow evaluating the requirement `::Assoc: Bar` - //~| ERROR overflow evaluating the requirement `::Assoc` [E0275] + //~^ ERROR overflow evaluating the requirement `::Assoc == _` + //~| ERROR overflow evaluating the requirement `::Assoc == _` + //~| ERROR overflow evaluating the requirement `::Assoc == _` + //~| ERROR overflow evaluating the requirement `::Assoc: Bar` } fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr index b0a0a69761aa4..80005d344ba39 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr @@ -11,7 +11,7 @@ note: required by a bound in `needs_bar` LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` -error[E0275]: overflow evaluating the requirement `::Assoc` +error[E0275]: overflow evaluating the requirement `::Assoc == _` --> $DIR/recursive-self-normalization.rs:11:5 | LL | needs_bar::(); @@ -19,6 +19,23 @@ LL | needs_bar::(); | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) -error: aborting due to 2 previous errors +error[E0275]: overflow evaluating the requirement `::Assoc == _` + --> $DIR/recursive-self-normalization.rs:11:5 + | +LL | needs_bar::(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0275]: overflow evaluating the requirement `::Assoc == _` + --> $DIR/recursive-self-normalization.rs:11:17 + | +LL | needs_bar::(); + | ^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0275`. From 3330940f7f2ec6ce7babd53240702406efaf13d1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 12 Jan 2024 08:04:22 +1100 Subject: [PATCH 2/9] Avoid repetition in `flush_delayed` calls. There are two places that handle normal delayed bugs. This commit factors out some repeated code. Also, we can use `std::mem::take` instead of `std::mem::replace`. --- compiler/rustc_errors/src/lib.rs | 35 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 404c89ea01b64..136c15acb35c2 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -519,6 +519,11 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { pub static TRACK_DIAGNOSTIC: AtomicRef = AtomicRef::new(&(default_track_diagnostic as _)); +enum DelayedBugKind { + Normal, + GoodPath, +} + #[derive(Copy, Clone, Default)] pub struct DiagCtxtFlags { /// If false, warning-level lints are suppressed. @@ -541,8 +546,7 @@ impl Drop for DiagCtxtInner { self.emit_stashed_diagnostics(); if !self.has_errors() { - let bugs = std::mem::replace(&mut self.span_delayed_bugs, Vec::new()); - self.flush_delayed(bugs, "no errors encountered even though `span_delayed_bug` issued"); + self.flush_delayed(DelayedBugKind::Normal) } // FIXME(eddyb) this explains what `good_path_delayed_bugs` are! @@ -551,11 +555,7 @@ impl Drop for DiagCtxtInner { // lints can be `#[allow]`'d, potentially leading to this triggering. // Also, "good path" should be replaced with a better naming. if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() { - let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new()); - self.flush_delayed( - bugs, - "no warnings or errors encountered even though `good_path_delayed_bugs` issued", - ); + self.flush_delayed(DelayedBugKind::GoodPath); } if self.check_unstable_expect_diagnostics { @@ -1218,9 +1218,7 @@ impl DiagCtxt { } pub fn flush_delayed(&self) { - let mut inner = self.inner.borrow_mut(); - let bugs = std::mem::replace(&mut inner.span_delayed_bugs, Vec::new()); - inner.flush_delayed(bugs, "no errors encountered even though `span_delayed_bug` issued"); + self.inner.borrow_mut().flush_delayed(DelayedBugKind::Normal); } } @@ -1396,11 +1394,18 @@ impl DiagCtxtInner { self.emit_diagnostic(Diagnostic::new(FailureNote, msg)); } - fn flush_delayed( - &mut self, - bugs: Vec, - explanation: impl Into + Copy, - ) { + fn flush_delayed(&mut self, kind: DelayedBugKind) { + let (bugs, explanation) = match kind { + DelayedBugKind::Normal => ( + std::mem::take(&mut self.span_delayed_bugs), + "no errors encountered even though `span_delayed_bug` issued", + ), + DelayedBugKind::GoodPath => ( + std::mem::take(&mut self.good_path_delayed_bugs), + "no warnings or errors encountered even though `good_path_delayed_bugs` issued", + ), + }; + if bugs.is_empty() { return; } From efab0dcb2582fced369a3cc991660760f49a4712 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 11 Jan 2024 17:15:21 -0800 Subject: [PATCH 3/9] Add more information to `visit_projection_elem` Without the starting place, it's hard to retrieve any useful information from visiting a projection. --- compiler/stable_mir/src/mir/body.rs | 33 +++++++++++++++------------- compiler/stable_mir/src/mir/visit.rs | 24 ++++++++++++++++---- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 72227a04bf189..38877f7a77fc4 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -963,7 +963,7 @@ pub enum PointerCoercion { /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, - /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. + /// Go from a non-capturing closure to a fn pointer or an unsafe fn pointer. /// It cannot convert a closure that requires unsafe. ClosureFnPointer(Safety), @@ -1037,21 +1037,24 @@ impl Place { /// locals from the function body where this place originates from. pub fn ty(&self, locals: &[LocalDecl]) -> Result { let start_ty = locals[self.local].ty; - self.projection.iter().fold(Ok(start_ty), |place_ty, elem| { - let ty = place_ty?; - match elem { - ProjectionElem::Deref => Self::deref_ty(ty), - ProjectionElem::Field(_idx, fty) => Ok(*fty), - ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { - Self::index_ty(ty) - } - ProjectionElem::Subslice { from, to, from_end } => { - Self::subslice_ty(ty, from, to, from_end) - } - ProjectionElem::Downcast(_) => Ok(ty), - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty), + self.projection.iter().fold(Ok(start_ty), |place_ty, elem| elem.ty(place_ty?)) + } +} + +impl ProjectionElem { + /// Get the expected type after applying this projection to a given place type. + pub fn ty(&self, place_ty: Ty) -> Result { + let ty = place_ty; + match &self { + ProjectionElem::Deref => Self::deref_ty(ty), + ProjectionElem::Field(_idx, fty) => Ok(*fty), + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty), + ProjectionElem::Subslice { from, to, from_end } => { + Self::subslice_ty(ty, from, to, from_end) } - }) + ProjectionElem::Downcast(_) => Ok(ty), + ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty), + } } fn index_ty(ty: Ty) -> Result { diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index ab57ff0f8f5d7..24296e9e8778b 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -37,7 +37,7 @@ use crate::mir::*; use crate::ty::{Const, GenericArgs, Region, Ty}; -use crate::{Opaque, Span}; +use crate::{Error, Opaque, Span}; pub trait MirVisitor { fn visit_body(&mut self, body: &Body) { @@ -76,12 +76,14 @@ pub trait MirVisitor { self.super_place(place, ptx, location) } - fn visit_projection_elem( + fn visit_projection_elem<'a>( &mut self, + place_ref: PlaceRef<'a>, elem: &ProjectionElem, ptx: PlaceContext, location: Location, ) { + let _ = place_ref; self.super_projection_elem(elem, ptx, location); } @@ -284,8 +286,9 @@ pub trait MirVisitor { let _ = ptx; self.visit_local(&place.local, ptx, location); - for elem in &place.projection { - self.visit_projection_elem(elem, ptx, location); + for (idx, elem) in place.projection.iter().enumerate() { + let place_ref = PlaceRef { local: place.local, projection: &place.projection[..idx] }; + self.visit_projection_elem(place_ref, elem, ptx, location); } } @@ -453,6 +456,19 @@ impl Location { } } +/// Reference to a place used to represent a partial projection. +pub struct PlaceRef<'a> { + pub local: Local, + pub projection: &'a [ProjectionElem], +} + +impl<'a> PlaceRef<'a> { + /// Get the type of this place. + pub fn ty(&self, locals: &[LocalDecl]) -> Result { + self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?)) + } +} + /// Information about a place's usage. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct PlaceContext { From eb79bc0470e0eefbc7608cffb99879969d68faea Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 12 Jan 2024 03:15:14 +0000 Subject: [PATCH 4/9] Good path bugs are just a flavor of delayed bug --- .../src/annotate_snippet_emitter_writer.rs | 2 +- compiler/rustc_errors/src/diagnostic.rs | 15 +++-- compiler/rustc_errors/src/lib.rs | 56 +++++++++++-------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 980ac31011931..648c9118400e9 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -85,7 +85,7 @@ fn source_string(file: Lrc, line: &Line) -> String { /// Maps `Diagnostic::Level` to `snippet::AnnotationType` fn annotation_type_for_level(level: Level) -> AnnotationType { match level { - Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error, + Level::Bug | Level::DelayedBug(_) | Level::Fatal | Level::Error => AnnotationType::Error, Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, Level::Help | Level::OnceHelp => AnnotationType::Help, diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index d8d6922a1bcda..786aced5b4f91 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,7 +1,7 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan, - SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, + CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, + MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; @@ -243,12 +243,15 @@ impl Diagnostic { pub fn is_error(&self) -> bool { match self.level { - Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error | Level::FailureNote => { - true - } + Level::Bug + | Level::DelayedBug(DelayedBugKind::Normal) + | Level::Fatal + | Level::Error + | Level::FailureNote => true, Level::ForceWarning(_) | Level::Warning + | Level::DelayedBug(DelayedBugKind::GoodPath) | Level::Note | Level::OnceNote | Level::Help @@ -318,7 +321,7 @@ impl Diagnostic { "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", self.level ); - self.level = Level::DelayedBug; + self.level = Level::DelayedBug(DelayedBugKind::Normal); } /// Appends a labeled span to the diagnostic. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 136c15acb35c2..aefebfec4487a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -519,7 +519,8 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { pub static TRACK_DIAGNOSTIC: AtomicRef = AtomicRef::new(&(default_track_diagnostic as _)); -enum DelayedBugKind { +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] +pub enum DelayedBugKind { Normal, GoodPath, } @@ -865,7 +866,8 @@ impl DiagCtxt { if treat_next_err_as_bug { self.bug(msg); } - DiagnosticBuilder::::new(self, DelayedBug, msg).emit() + DiagnosticBuilder::::new(self, DelayedBug(DelayedBugKind::Normal), msg) + .emit() } /// Like `delayed_bug`, but takes an additional span. @@ -882,16 +884,15 @@ impl DiagCtxt { if treat_next_err_as_bug { self.span_bug(sp, msg); } - DiagnosticBuilder::::new(self, DelayedBug, msg).with_span(sp).emit() + DiagnosticBuilder::::new(self, DelayedBug(DelayedBugKind::Normal), msg) + .with_span(sp) + .emit() } // FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's // where the explanation of what "good path" is (also, it should be renamed). pub fn good_path_delayed_bug(&self, msg: impl Into) { - let mut inner = self.inner.borrow_mut(); - let diagnostic = Diagnostic::new(DelayedBug, msg); - let backtrace = std::backtrace::Backtrace::capture(); - inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); + DiagnosticBuilder::<()>::new(self, DelayedBug(DelayedBugKind::GoodPath), msg).emit() } #[track_caller] @@ -1268,17 +1269,27 @@ impl DiagCtxtInner { return None; } - if diagnostic.level == DelayedBug { - // FIXME(eddyb) this should check for `has_errors` and stop pushing - // once *any* errors were emitted (and truncate `span_delayed_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::capture(); - self.span_delayed_bugs - .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); + // FIXME(eddyb) this should check for `has_errors` and stop pushing + // once *any* errors were emitted (and truncate `span_delayed_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. + match diagnostic.level { + DelayedBug(DelayedBugKind::Normal) => { + let backtrace = std::backtrace::Backtrace::capture(); + self.span_delayed_bugs + .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); - #[allow(deprecated)] - return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + #[allow(deprecated)] + return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + } + DelayedBug(DelayedBugKind::GoodPath) => { + let backtrace = std::backtrace::Backtrace::capture(); + self.good_path_delayed_bugs + .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); + + return None; + } + _ => {} } if diagnostic.has_future_breakage() { @@ -1438,7 +1449,7 @@ impl DiagCtxtInner { if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner }; // "Undelay" the `DelayedBug`s (into plain `Bug`s). - if bug.level != DelayedBug { + if !matches!(bug.level, DelayedBug(_)) { // NOTE(eddyb) not panicking here because we're already producing // an ICE, and the more information the merrier. bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel { @@ -1526,8 +1537,9 @@ pub enum Level { /// silently dropped. I.e. "expect other errors are emitted" semantics. Useful on code paths /// that should only be reached when compiling erroneous code. /// - /// Its `EmissionGuarantee` is `ErrorGuaranteed`. - DelayedBug, + /// Its `EmissionGuarantee` is `ErrorGuaranteed` for `Normal` delayed bugs, and `()` for + /// `GoodPath` delayed bugs. + DelayedBug(DelayedBugKind), /// An error that causes an immediate abort. Used for things like configuration errors, /// internal overflows, some file operation errors. @@ -1602,7 +1614,7 @@ impl Level { fn color(self) -> ColorSpec { let mut spec = ColorSpec::new(); match self { - Bug | DelayedBug | Fatal | Error => { + Bug | DelayedBug(_) | Fatal | Error => { spec.set_fg(Some(Color::Red)).set_intense(true); } ForceWarning(_) | Warning => { @@ -1622,7 +1634,7 @@ impl Level { pub fn to_str(self) -> &'static str { match self { - Bug | DelayedBug => "error: internal compiler error", + Bug | DelayedBug(_) => "error: internal compiler error", Fatal | Error => "error", ForceWarning(_) | Warning => "warning", Note | OnceNote => "note", From 7df43d3c814b4d4a2d0231a5d02fe36e70901627 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 12 Jan 2024 00:30:04 +0000 Subject: [PATCH 5/9] Give me a way to emit all the delayed bugs --- compiler/rustc_errors/src/lib.rs | 6 ++++ compiler/rustc_session/src/config.rs | 1 + compiler/rustc_session/src/options.rs | 3 ++ tests/ui/treat-err-as-bug/eagerly-emit.rs | 11 ++++++++ tests/ui/treat-err-as-bug/eagerly-emit.stderr | 28 +++++++++++++++++++ 5 files changed, 49 insertions(+) create mode 100644 tests/ui/treat-err-as-bug/eagerly-emit.rs create mode 100644 tests/ui/treat-err-as-bug/eagerly-emit.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index aefebfec4487a..8c2752af65974 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -533,6 +533,9 @@ pub struct DiagCtxtFlags { /// If Some, the Nth error-level diagnostic is upgraded to bug-level. /// (rustc: see `-Z treat-err-as-bug`) pub treat_err_as_bug: Option, + /// Eagerly emit delayed bugs as errors, so that the compiler debugger may + /// see all of the errors being emitted at once. + pub eagerly_emit_delayed_bugs: bool, /// Show macro backtraces. /// (rustc: see `-Z macro-backtrace`) pub macro_backtrace: bool, @@ -1274,6 +1277,9 @@ impl DiagCtxtInner { // when an error is first emitted, also), but maybe there's a case // in which that's not sound? otherwise this is really inefficient. match diagnostic.level { + DelayedBug(_) if self.flags.eagerly_emit_delayed_bugs => { + diagnostic.level = Error; + } DelayedBug(DelayedBugKind::Normal) => { let backtrace = std::backtrace::Backtrace::capture(); self.span_delayed_bugs diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 61796d7a6cafc..8918dce7d3a41 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1146,6 +1146,7 @@ impl UnstableOptions { DiagCtxtFlags { can_emit_warnings, treat_err_as_bug: self.treat_err_as_bug, + eagerly_emit_delayed_bugs: self.eagerly_emit_delayed_bugs, macro_backtrace: self.macro_backtrace, deduplicate_diagnostics: self.deduplicate_diagnostics, track_diagnostics: self.track_diagnostics, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c97b18ebd66ad..2d91a3fbd9116 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1583,6 +1583,9 @@ options! { "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), dylib_lto: bool = (false, parse_bool, [UNTRACKED], "enables LTO for dylib crate type"), + eagerly_emit_delayed_bugs: bool = (false, parse_bool, [UNTRACKED], + "emit delayed bugs eagerly as errors instead of stashing them and emitting \ + them only if an error has not been emitted"), ehcont_guard: bool = (false, parse_bool, [TRACKED], "generate Windows EHCont Guard tables"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], diff --git a/tests/ui/treat-err-as-bug/eagerly-emit.rs b/tests/ui/treat-err-as-bug/eagerly-emit.rs new file mode 100644 index 0000000000000..5f32f5a1d94b7 --- /dev/null +++ b/tests/ui/treat-err-as-bug/eagerly-emit.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zeagerly-emit-delayed-bugs + +trait Foo {} + +fn main() {} + +fn f() -> impl Foo { + //~^ ERROR the trait bound `i32: Foo` is not satisfied + //~| ERROR `report_selection_error` did not emit an error + 1i32 +} diff --git a/tests/ui/treat-err-as-bug/eagerly-emit.stderr b/tests/ui/treat-err-as-bug/eagerly-emit.stderr new file mode 100644 index 0000000000000..3d25741d52de8 --- /dev/null +++ b/tests/ui/treat-err-as-bug/eagerly-emit.stderr @@ -0,0 +1,28 @@ +error: `report_selection_error` did not emit an error + --> $DIR/eagerly-emit.rs:7:11 + | +LL | fn f() -> impl Foo { + | ^^^^^^^^ + +error: trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging + +error[E0277]: the trait bound `i32: Foo` is not satisfied + --> $DIR/eagerly-emit.rs:7:11 + | +LL | fn f() -> impl Foo { + | ^^^^^^^^ the trait `Foo` is not implemented for `i32` +... +LL | 1i32 + | ---- return type was inferred to be `i32` here + | +help: this trait has no implementations, consider adding one + --> $DIR/eagerly-emit.rs:3:1 + | +LL | trait Foo {} + | ^^^^^^^^^ + +error: expected fulfillment errors + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. From 462bcac629752d4f5d8bf87adcba9dab96044ed5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 12 Jan 2024 11:02:57 +0100 Subject: [PATCH 6/9] Rename `--env` option flag to `--env-set` --- compiler/rustc_builtin_macros/src/env.rs | 2 +- compiler/rustc_session/src/config.rs | 6 +++--- .../src/compiler-flags/{env.md => env-set.md} | 14 +++++++------- tests/ui/extenv/extenv-env-overload.rs | 2 +- tests/ui/extenv/extenv-env.rs | 2 +- tests/ui/extenv/extenv-not-env.rs | 2 +- tests/ui/feature-gates/env-flag.rs | 2 +- tests/ui/feature-gates/env-flag.stderr | 2 +- tests/ui/proc-macro/env.rs | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) rename src/doc/unstable-book/src/compiler-flags/{env.md => env-set.md} (82%) diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 4b3eaf7855700..a0fd0e3f9be08 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -18,7 +18,7 @@ fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Option { if let Some(value) = cx.sess.opts.logical_env.get(var) { return Some(Symbol::intern(value)); } - // If the environment variable was not defined with the `--env` option, we try to retrieve it + // If the environment variable was not defined with the `--env-set` option, we try to retrieve it // from rustc's environment. env::var(var).ok().as_deref().map(Symbol::intern) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 61796d7a6cafc..ba04a3222ba9d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1823,7 +1823,7 @@ pub fn rustc_optgroups() -> Vec { "Remap source names in all output (compiler messages and output files)", "FROM=TO", ), - opt::multi("", "env", "Inject an environment variable", "VAR=VALUE"), + opt::multi("", "env-set", "Inject an environment variable", "VAR=VALUE"), ]); opts } @@ -2599,11 +2599,11 @@ fn parse_logical_env( ) -> FxIndexMap { let mut vars = FxIndexMap::default(); - for arg in matches.opt_strs("env") { + for arg in matches.opt_strs("env-set") { if let Some((name, val)) = arg.split_once('=') { vars.insert(name.to_string(), val.to_string()); } else { - early_dcx.early_fatal(format!("`--env`: specify value for variable `{arg}`")); + early_dcx.early_fatal(format!("`--env-set`: specify value for variable `{arg}`")); } } diff --git a/src/doc/unstable-book/src/compiler-flags/env.md b/src/doc/unstable-book/src/compiler-flags/env-set.md similarity index 82% rename from src/doc/unstable-book/src/compiler-flags/env.md rename to src/doc/unstable-book/src/compiler-flags/env-set.md index ac6d7474a9ba7..e5d7206c3a340 100644 --- a/src/doc/unstable-book/src/compiler-flags/env.md +++ b/src/doc/unstable-book/src/compiler-flags/env-set.md @@ -1,4 +1,4 @@ -# `env` +# `env-set` The tracking issue for this feature is: [#118372](https://github.com/rust-lang/rust/issues/118372). @@ -11,11 +11,11 @@ from the `proc_macro` crate. This information will be stored in the dep-info files. For more information about dep-info files, take a look [here](https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files). -When retrieving an environment variable value, the one specified by `--env` will take +When retrieving an environment variable value, the one specified by `--env-set` will take precedence. For example, if you want have `PATH=a` in your environment and pass: ```bash -rustc --env PATH=env +rustc --env-set PATH=env ``` Then you will have: @@ -24,17 +24,17 @@ Then you will have: assert_eq!(env!("PATH"), "env"); ``` -It will trigger a new compilation if any of the `--env` argument value is different. +It will trigger a new compilation if any of the `--env-set` argument value is different. So if you first passed: ```bash ---env A=B --env X=12 +--env-set A=B --env X=12 ``` and then on next compilation: ```bash ---env A=B +--env-set A=B ``` `X` value is different (not set) so the code will be re-compiled. @@ -42,4 +42,4 @@ and then on next compilation: Please note that on Windows, environment variables are case insensitive but case preserving whereas `rustc`'s environment variables are case sensitive. For example, having `Path` in your environment (case insensitive) is different than using -`rustc --env Path=...` (case sensitive). +`rustc --env-set Path=...` (case sensitive). diff --git a/tests/ui/extenv/extenv-env-overload.rs b/tests/ui/extenv/extenv-env-overload.rs index b82bb2fe9661a..8b3b565fe83f0 100644 --- a/tests/ui/extenv/extenv-env-overload.rs +++ b/tests/ui/extenv/extenv-env-overload.rs @@ -1,6 +1,6 @@ // run-pass // rustc-env:MY_VAR=tadam -// compile-flags: --env MY_VAR=123abc -Zunstable-options +// compile-flags: --env-set MY_VAR=123abc -Zunstable-options // This test ensures that variables provided with `--env` take precedence over // variables from environment. diff --git a/tests/ui/extenv/extenv-env.rs b/tests/ui/extenv/extenv-env.rs index 9fda52b894111..051ea214c1bd0 100644 --- a/tests/ui/extenv/extenv-env.rs +++ b/tests/ui/extenv/extenv-env.rs @@ -1,4 +1,4 @@ -// compile-flags: --env FOO=123abc -Zunstable-options +// compile-flags: --env-set FOO=123abc -Zunstable-options // run-pass fn main() { assert_eq!(env!("FOO"), "123abc"); diff --git a/tests/ui/extenv/extenv-not-env.rs b/tests/ui/extenv/extenv-not-env.rs index d6c4a43b0032a..b0355e073e40e 100644 --- a/tests/ui/extenv/extenv-not-env.rs +++ b/tests/ui/extenv/extenv-not-env.rs @@ -1,6 +1,6 @@ // run-pass // rustc-env:MY_ENV=/ -// Ensures that variables not defined through `--env` are still available. +// Ensures that variables not defined through `--env-set` are still available. fn main() { assert!(!env!("MY_ENV").is_empty()); diff --git a/tests/ui/feature-gates/env-flag.rs b/tests/ui/feature-gates/env-flag.rs index 9dfda2584fbc2..598773cf3e4cc 100644 --- a/tests/ui/feature-gates/env-flag.rs +++ b/tests/ui/feature-gates/env-flag.rs @@ -1,3 +1,3 @@ -// compile-flags: --env A=B +// compile-flags: --env-set A=B fn main() {} diff --git a/tests/ui/feature-gates/env-flag.stderr b/tests/ui/feature-gates/env-flag.stderr index 5cb18cef9fbc2..a9fa1b65ea18c 100644 --- a/tests/ui/feature-gates/env-flag.stderr +++ b/tests/ui/feature-gates/env-flag.stderr @@ -1,2 +1,2 @@ -error: the `-Z unstable-options` flag must also be passed to enable the flag `env` +error: the `-Z unstable-options` flag must also be passed to enable the flag `env-set` diff --git a/tests/ui/proc-macro/env.rs b/tests/ui/proc-macro/env.rs index 1b1d1873eb34b..c0edda4f7df23 100644 --- a/tests/ui/proc-macro/env.rs +++ b/tests/ui/proc-macro/env.rs @@ -1,7 +1,7 @@ // aux-build:env.rs // run-pass // rustc-env: THE_CONST=1 -// compile-flags: -Zunstable-options --env THE_CONST=12 --env ANOTHER=4 +// compile-flags: -Zunstable-options --env-set THE_CONST=12 --env-set ANOTHER=4 #![crate_name = "foo"] From 6d29eac04b5c5bacdb4a92b3d02c78695ed4d829 Mon Sep 17 00:00:00 2001 From: DianQK Date: Fri, 12 Jan 2024 18:22:39 +0800 Subject: [PATCH 7/9] Revert "Auto merge of #118568 - DianQK:no-builtins-symbols, r=pnkfelix" This reverts commit 503e129328080e924c0ddfca6abf4c2812580102, reversing changes made to 0e7f91b75e7484a713e2f644212cfc1aa7478a28. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- .../src/back/symbol_export.rs | 18 +++--------------- .../src/middle/exported_symbols.rs | 5 ----- src/tools/miri/src/bin/miri.rs | 1 - tests/run-make/no-builtins-symbols/Makefile | 7 ------- tests/run-make/no-builtins-symbols/main.rs | 1 - 6 files changed, 4 insertions(+), 30 deletions(-) delete mode 100644 tests/run-make/no-builtins-symbols/Makefile delete mode 100644 tests/run-make/no-builtins-symbols/main.rs diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index e9e8ade09b77b..42bd8687042a1 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -60,7 +60,7 @@ fn prepare_lto( }; let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| { - if info.level.is_below_threshold(export_threshold) || info.used || info.used_compiler { + if info.level.is_below_threshold(export_threshold) || info.used { Some(CString::new(name.as_str()).unwrap()) } else { None diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 94841ab7b33e0..ffa37f1cc165d 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -105,21 +105,20 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap, _: LocalCrate) -> DefIdMap, _: LocalCrate) -> DefIdMap Date: Fri, 12 Jan 2024 18:23:04 +0800 Subject: [PATCH 8/9] Revert "Auto merge of #113923 - DianQK:restore-no-builtins-lto, r=pnkfelix" This reverts commit 8c2b57721728233e074db69d93517614de338055, reversing changes made to 9cf18e98f82d85fa41141391d54485b8747da46f. --- compiler/rustc_codegen_llvm/src/back/write.rs | 8 ++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +++- compiler/rustc_codegen_ssa/src/back/link.rs | 46 ++++++++++++++----- .../src/back/symbol_export.rs | 10 ++-- compiler/rustc_codegen_ssa/src/back/write.rs | 16 ++++++- compiler/rustc_codegen_ssa/src/base.rs | 8 +++- compiler/rustc_codegen_ssa/src/lib.rs | 3 +- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 9 +++- tests/run-make/no-builtins-lto/Makefile | 18 +++----- .../no-builtins-lto/filecheck.lto.txt | 17 ------- tests/run-make/no-builtins-lto/foo.rs | 33 ------------- tests/run-make/no-builtins-lto/main.rs | 28 +---------- tests/run-make/no-builtins-lto/no_builtins.rs | 13 ------ .../Makefile | 0 .../main.rs | 5 +- .../verify.js | 0 16 files changed, 89 insertions(+), 133 deletions(-) delete mode 100644 tests/run-make/no-builtins-lto/filecheck.lto.txt delete mode 100644 tests/run-make/no-builtins-lto/foo.rs rename tests/run-make/{wasm-builtins-import => wasm-spurious-import}/Makefile (100%) rename tests/run-make/{wasm-builtins-import => wasm-spurious-import}/main.rs (61%) rename tests/run-make/{wasm-builtins-import => wasm-spurious-import}/verify.js (100%) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a912ef9e7558e..27cb0366f17dc 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -569,6 +569,7 @@ pub(crate) unsafe fn llvm_optimize( unroll_loops, config.vectorize_slp, config.vectorize_loop, + config.no_builtins, config.emit_lifetime_markers, sanitizer_options.as_ref(), pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), @@ -677,6 +678,7 @@ pub(crate) unsafe fn codegen( unsafe fn with_codegen<'ll, F, R>( tm: &'ll llvm::TargetMachine, llmod: &'ll llvm::Module, + no_builtins: bool, f: F, ) -> R where @@ -684,7 +686,7 @@ pub(crate) unsafe fn codegen( { let cpm = llvm::LLVMCreatePassManager(); llvm::LLVMAddAnalysisPasses(tm, cpm); - llvm::LLVMRustAddLibraryInfo(cpm, llmod); + llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); f(cpm) } @@ -785,7 +787,7 @@ pub(crate) unsafe fn codegen( } else { llmod }; - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file( dcx, tm, @@ -820,7 +822,7 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file( dcx, tm, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index aefca6b34f577..ee73c6b4756f0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2173,8 +2173,13 @@ extern "C" { ArgsCstrBuff: *const c_char, ArgsCstrBuffLen: usize, ) -> *mut TargetMachine; + pub fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine); - pub fn LLVMRustAddLibraryInfo<'a>(PM: &PassManager<'a>, M: &'a Module); + pub fn LLVMRustAddLibraryInfo<'a>( + PM: &PassManager<'a>, + M: &'a Module, + DisableSimplifyLibCalls: bool, + ); pub fn LLVMRustWriteOutputFile<'a>( T: &'a TargetMachine, PM: &PassManager<'a>, @@ -2196,6 +2201,7 @@ extern "C" { UnrollLoops: bool, SLPVectorize: bool, LoopVectorize: bool, + DisableSimplifyLibCalls: bool, EmitLifetimeMarkers: bool, SanitizerOptions: Option<&SanitizerOptions>, PGOGenPath: *const c_char, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 70fda982b012e..ace356ab1533f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -270,14 +270,8 @@ pub fn each_linked_rlib( for &cnum in crates { match fmts.get(cnum.as_usize() - 1) { - Some(&Linkage::NotLinked | &Linkage::Dynamic) => continue, - Some(&Linkage::IncludedFromDylib) => { - // We always link crate `compiler_builtins` statically. When enabling LTO, we include it as well. - if info.compiler_builtins != Some(cnum) { - continue; - } - } - Some(&Linkage::Static) => {} + Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue, + Some(_) => {} None => return Err(errors::LinkRlibError::MissingFormat), } let crate_name = info.crate_name[&cnum]; @@ -526,7 +520,8 @@ fn link_staticlib<'a>( &codegen_results.crate_info, Some(CrateType::Staticlib), &mut |cnum, path| { - let lto = are_upstream_rust_objects_already_included(sess); + let lto = are_upstream_rust_objects_already_included(sess) + && !ignored_for_lto(sess, &codegen_results.crate_info, cnum); let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter(); let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib)); @@ -1277,6 +1272,24 @@ fn link_sanitizer_runtime( } } +/// Returns a boolean indicating whether the specified crate should be ignored +/// during LTO. +/// +/// Crates ignored during LTO are not lumped together in the "massive object +/// file" that we create and are linked in their normal rlib states. See +/// comments below for what crates do not participate in LTO. +/// +/// It's unusual for a crate to not participate in LTO. Typically only +/// compiler-specific and unstable crates have a reason to not participate in +/// LTO. +pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool { + // If our target enables builtin function lowering in LLVM then the + // crates providing these functions don't participate in LTO (e.g. + // no_builtins or compiler builtins crates). + !sess.target.no_builtins + && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum)) +} + /// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { fn infer_from( @@ -2742,6 +2755,10 @@ fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf { // symbols). We must continue to include the rest of the rlib, however, as // it may contain static native libraries which must be linked in. // +// (*) Crates marked with `#![no_builtins]` don't participate in LTO and +// their bytecode wasn't included. The object files in those libraries must +// still be passed to the linker. +// // Note, however, that if we're not doing LTO we can just pass the rlib // blindly to the linker (fast) because it's fine if it's not actually // included as we're at the end of the dependency chain. @@ -2767,7 +2784,9 @@ fn add_static_crate<'a>( cmd.link_rlib(&rlib_path); }; - if !are_upstream_rust_objects_already_included(sess) { + if !are_upstream_rust_objects_already_included(sess) + || ignored_for_lto(sess, &codegen_results.crate_info, cnum) + { link_upstream(cratepath); return; } @@ -2781,6 +2800,8 @@ fn add_static_crate<'a>( let canonical_name = name.replace('-', "_"); let upstream_rust_objects_already_included = are_upstream_rust_objects_already_included(sess); + let is_builtins = + sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum); let mut archive = archive_builder_builder.new_archive_builder(sess); if let Err(error) = archive.add_archive( @@ -2797,8 +2818,9 @@ fn add_static_crate<'a>( // If we're performing LTO and this is a rust-generated object // file, then we don't need the object file as it's part of the - // LTO module. - if upstream_rust_objects_already_included && is_rust_object { + // LTO module. Note that `#![no_builtins]` is excluded from LTO, + // though, so we let that object file slide. + if upstream_rust_objects_already_included && is_rust_object && is_builtins { return true; } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index ffa37f1cc165d..cae7c40c5ad19 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -54,8 +54,8 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap = tcx .reachable_set(()) @@ -107,11 +107,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap( let mut each_linked_rlib_for_lto = Vec::new(); drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| { + if link::ignored_for_lto(sess, crate_info, cnum) { + return; + } each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); })); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 9d1729c4b542d..0ad4af968dbfd 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -859,6 +859,7 @@ impl CrateInfo { local_crate_name, compiler_builtins, profiler_runtime: None, + is_no_builtins: Default::default(), native_libraries: Default::default(), used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), crate_name: Default::default(), @@ -885,6 +886,9 @@ impl CrateInfo { if tcx.is_profiler_runtime(cnum) { info.profiler_runtime = Some(cnum); } + if tcx.is_no_builtins(cnum) { + info.is_no_builtins.insert(cnum); + } } // Handle circular dependencies in the standard library. @@ -892,7 +896,9 @@ impl CrateInfo { // If global LTO is enabled then almost everything (*) is glued into a single object file, // so this logic is not necessary and can cause issues on some targets (due to weak lang // item symbols being "privatized" to that object file), so we disable it. - // (*) Native libs are not glued, and we assume that they cannot define weak lang items. + // (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued, + // and we assume that they cannot define weak lang items. This is not currently enforced + // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { let missing_weak_lang_items: FxHashSet = info diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 0d88df632803f..99280fdba7ce1 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -25,7 +25,7 @@ extern crate tracing; extern crate rustc_middle; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; @@ -158,6 +158,7 @@ pub struct CrateInfo { pub local_crate_name: Symbol, pub compiler_builtins: Option, pub profiler_runtime: Option, + pub is_no_builtins: FxHashSet, pub native_libraries: FxHashMap>, pub crate_name: FxHashMap, pub used_libraries: Vec, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 76eb6bfaef721..6114f7c867807 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -531,9 +531,12 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { // Unfortunately, the LLVM C API doesn't provide a way to create the // TargetLibraryInfo pass, so we use this method to do so. -extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M) { +extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M, + bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); TargetLibraryInfoImpl TLII(TargetTriple); + if (DisableSimplifyLibCalls) + TLII.disableAllFunctions(); unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII)); } @@ -700,7 +703,7 @@ LLVMRustOptimize( bool IsLinkerPluginLTO, bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers, bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, - bool EmitLifetimeMarkers, + bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, const char *PGOUsePath, bool InstrumentCoverage, const char *InstrProfileOutput, @@ -800,6 +803,8 @@ LLVMRustOptimize( Triple TargetTriple(TheModule->getTargetTriple()); std::unique_ptr TLII(new TargetLibraryInfoImpl(TargetTriple)); + if (DisableSimplifyLibCalls) + TLII->disableAllFunctions(); FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); PB.registerModuleAnalyses(MAM); diff --git a/tests/run-make/no-builtins-lto/Makefile b/tests/run-make/no-builtins-lto/Makefile index c7be4836466db..c8f05d9918b91 100644 --- a/tests/run-make/no-builtins-lto/Makefile +++ b/tests/run-make/no-builtins-lto/Makefile @@ -1,15 +1,9 @@ include ../tools.mk -# only-x86_64 - -# We want to check that `no_builtins` is correctly participating in LTO. -# First, verify that the `foo::foo` symbol can be found when linking. -# Next, verify that `memcpy` can be customized using `no_builtins` under LTO. -# Others will use the built-in memcpy. - all: - $(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 foo.rs - $(RUSTC) -C linker-plugin-lto -C opt-level=2 -C debuginfo=0 no_builtins.rs - $(RUSTC) main.rs -C lto -C opt-level=2 -C debuginfo=0 -C save-temps -C metadata=1 -C codegen-units=1 - "$(LLVM_BIN_DIR)"/llvm-dis $(TMPDIR)/main.main.*-cgu.0.rcgu.lto.input.bc -o $(TMPDIR)/lto.ll - cat "$(TMPDIR)"/lto.ll | "$(LLVM_FILECHECK)" filecheck.lto.txt + # Compile a `#![no_builtins]` rlib crate + $(RUSTC) no_builtins.rs + # Build an executable that depends on that crate using LTO. The no_builtins crate doesn't + # participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by + # grepping the linker arguments. + $(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib' diff --git a/tests/run-make/no-builtins-lto/filecheck.lto.txt b/tests/run-make/no-builtins-lto/filecheck.lto.txt deleted file mode 100644 index 79dc3a51501db..0000000000000 --- a/tests/run-make/no-builtins-lto/filecheck.lto.txt +++ /dev/null @@ -1,17 +0,0 @@ -CHECK: define{{.*}} void @bar -CHECK-NEXT: call void @no_builtins -CHECK-NEXT: call void @llvm.memcpy - -CHECK: define{{.*}} i32 @main -CHECK: call void @bar - -CHECK: define{{.*}} void @foo -CHECK-NEXT: call void @llvm.memcpy - -CHECK: define{{.*}} void @no_builtins -CHECK-SAME: #[[ATTR:[0-9]+]] { -CHECK: call void @foo -CHECK-NEXT: call{{.*}} @memcpy - -CHECK: attributes #[[ATTR]] -CHECK-SAME: no-builtins diff --git a/tests/run-make/no-builtins-lto/foo.rs b/tests/run-make/no-builtins-lto/foo.rs deleted file mode 100644 index f09ac40b152a2..0000000000000 --- a/tests/run-make/no-builtins-lto/foo.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![feature(lang_items, no_core)] -#![no_std] -#![no_core] -#![crate_type = "lib"] - -#[inline(never)] -#[no_mangle] -pub unsafe fn foo(dest: *mut u8, src: *const u8) { - // should call `@llvm.memcpy`. - memcpy(dest, src, 1024); -} - -#[no_mangle] -#[inline(never)] -pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, _n: usize) -> *mut u8 { - *dest = 0; - return src as *mut u8; -} - -#[lang = "sized"] -trait Sized {} -#[lang = "copy"] -trait Copy {} -impl Copy for *mut u8 {} -impl Copy for *const u8 {} - -#[lang = "drop_in_place"] -#[allow(unconditional_recursion)] -pub unsafe fn drop_in_place(to_drop: *mut T) { - // Code here does not matter - this is replaced by the - // real drop glue by the compiler. - drop_in_place(to_drop); -} diff --git a/tests/run-make/no-builtins-lto/main.rs b/tests/run-make/no-builtins-lto/main.rs index 4421a2afbce68..890c999c8ccf7 100644 --- a/tests/run-make/no-builtins-lto/main.rs +++ b/tests/run-make/no-builtins-lto/main.rs @@ -1,29 +1,3 @@ -#![feature(no_core, start, lang_items)] -#![no_std] -// We use `no_core` to reduce the LTO products is small enough. -#![no_core] - extern crate no_builtins; -extern crate foo; - -#[cfg_attr(unix, link(name = "c"))] -#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] -extern "C" {} - -#[start] -fn main(_: isize, p: *const *const u8) -> isize { - // Make sure the symbols are retained. - unsafe { bar(*p as *mut u8, *p); } - 0 -} - -#[no_mangle] -#[inline(never)] -pub unsafe extern "C" fn bar(dest: *mut u8, src: *const u8) { - no_builtins::no_builtins(dest, src); - // should call `@llvm.memcpy` - foo::memcpy(dest, src, 1024); -} -#[lang = "eh_personality"] -fn eh_personality() {} +fn main() {} diff --git a/tests/run-make/no-builtins-lto/no_builtins.rs b/tests/run-make/no-builtins-lto/no_builtins.rs index 33ed68e3aee3d..5d001031a57fa 100644 --- a/tests/run-make/no-builtins-lto/no_builtins.rs +++ b/tests/run-make/no-builtins-lto/no_builtins.rs @@ -1,15 +1,2 @@ -#![feature(lang_items, no_core)] -#![no_std] -#![no_core] #![crate_type = "lib"] #![no_builtins] - -extern crate foo; - -#[no_mangle] -pub unsafe fn no_builtins(dest: *mut u8, src: *const u8) { - // There should be no "undefined reference to `foo::foo'". - foo::foo(dest, src); - // should call `@memcpy` instead of `@llvm.memcpy`. - foo::memcpy(dest, src, 1024); -} diff --git a/tests/run-make/wasm-builtins-import/Makefile b/tests/run-make/wasm-spurious-import/Makefile similarity index 100% rename from tests/run-make/wasm-builtins-import/Makefile rename to tests/run-make/wasm-spurious-import/Makefile diff --git a/tests/run-make/wasm-builtins-import/main.rs b/tests/run-make/wasm-spurious-import/main.rs similarity index 61% rename from tests/run-make/wasm-builtins-import/main.rs rename to tests/run-make/wasm-spurious-import/main.rs index 5eb99df6ff74c..fcbead5e28bd2 100644 --- a/tests/run-make/wasm-builtins-import/main.rs +++ b/tests/run-make/wasm-spurious-import/main.rs @@ -8,8 +8,7 @@ fn my_panic(_info: &core::panic::PanicInfo) -> ! { #[no_mangle] pub fn multer(a: i128, b: i128) -> i128 { - // Trigger usage of the __multi3 compiler intrinsic which then leads to an imported function - // such as panic or __multi3 (externally defined) in case of a bug. We verify that - // no imports exist in our verifier. + // Trigger usage of the __multi3 compiler intrinsic which then leads to an imported + // panic function in case of a bug. We verify that no imports exist in our verifier. a * b } diff --git a/tests/run-make/wasm-builtins-import/verify.js b/tests/run-make/wasm-spurious-import/verify.js similarity index 100% rename from tests/run-make/wasm-builtins-import/verify.js rename to tests/run-make/wasm-spurious-import/verify.js From ca421fe1d3cba0dbd1b0dcc52c3d040fce63971a Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 11 Jan 2024 00:24:46 +0800 Subject: [PATCH 9/9] check rust lints when an unknown lint is detected --- compiler/rustc_lint/messages.ftl | 10 +++++-- compiler/rustc_lint/src/context.rs | 24 +++++++++++----- compiler/rustc_lint/src/levels.rs | 9 +++--- compiler/rustc_lint/src/lints.rs | 3 +- compiler/rustc_span/src/edit_distance.rs | 28 +++++++++++++++++++ .../tests/ui/unknown_clippy_lints.fixed | 6 ++-- .../clippy/tests/ui/unknown_clippy_lints.rs | 4 ++- .../tests/ui/unknown_clippy_lints.stderr | 20 +++++++++++-- 8 files changed, 85 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 40e6b1b579f5b..b6fa2f1f22163 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -532,8 +532,14 @@ lint_unknown_gated_lint = lint_unknown_lint = unknown lint: `{$name}` - .suggestion = did you mean - .help = did you mean: `{$replace}` + .suggestion = {$from_rustc -> + [true] a lint with a similar name exists in `rustc` lints + *[false] did you mean + } + .help = {$from_rustc -> + [true] a lint with a similar name exists in `rustc` lints: `{$replace}` + *[false] did you mean: `{$replace}` + } lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` .help = add `#![register_tool({$tool_name})]` to the crate root diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d0fd019a8b122..ffd8f1b3c79c5 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -33,7 +33,7 @@ use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, Ty use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::{LintStoreMarker, Session}; -use rustc_span::edit_distance::find_best_match_for_name; +use rustc_span::edit_distance::find_best_match_for_names; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi; @@ -117,7 +117,7 @@ struct LintGroup { pub enum CheckLintNameResult<'a> { Ok(&'a [LintId]), /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name. - NoLint(Option), + NoLint(Option<(Symbol, bool)>), /// The lint refers to a tool that has not been registered. NoTool, /// The lint has been renamed to a new name. @@ -377,7 +377,7 @@ impl LintStore { debug!("lints={:?}", self.by_name.keys().collect::>()); let tool_prefix = format!("{tool_name}::"); return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) { - self.no_lint_suggestion(&complete_name) + self.no_lint_suggestion(&complete_name, tool_name.as_str()) } else { // 2. The tool isn't currently running, so no lints will be registered. // To avoid giving a false positive, ignore all unknown lints. @@ -419,13 +419,14 @@ impl LintStore { } } - fn no_lint_suggestion(&self, lint_name: &str) -> CheckLintNameResult<'_> { + fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> { let name_lower = lint_name.to_lowercase(); if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() { // First check if the lint name is (partly) in upper case instead of lower case... - return CheckLintNameResult::NoLint(Some(Symbol::intern(&name_lower))); + return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false))); } + // ...if not, search for lints with a similar name // Note: find_best_match_for_name depends on the sort order of its input vector. // To ensure deterministic output, sort elements of the lint_groups hash map. @@ -441,7 +442,16 @@ impl LintStore { let groups = groups.iter().map(|k| Symbol::intern(k)); let lints = self.lints.iter().map(|l| Symbol::intern(&l.name_lower())); let names: Vec = groups.chain(lints).collect(); - let suggestion = find_best_match_for_name(&names, Symbol::intern(&name_lower), None); + let mut lookups = vec![Symbol::intern(&name_lower)]; + if let Some(stripped) = name_lower.split("::").last() { + lookups.push(Symbol::intern(stripped)); + } + let res = find_best_match_for_names(&names, &lookups, None); + let is_rustc = res.map_or_else( + || false, + |s| name_lower.contains("::") && !s.as_str().starts_with(tool_name), + ); + let suggestion = res.map(|s| (s, is_rustc)); CheckLintNameResult::NoLint(suggestion) } @@ -454,7 +464,7 @@ impl LintStore { match self.by_name.get(&complete_name) { None => match self.lint_groups.get(&*complete_name) { // Now we are sure, that this lint exists nowhere - None => self.no_lint_suggestion(lint_name), + None => self.no_lint_suggestion(lint_name, tool_name), Some(LintGroup { lint_ids, depr, .. }) => { // Reaching this would be weird, but let's cover this case anyway if let Some(LintAlias { name, silent }) = depr { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 49821437b7657..3c2d0c7b20536 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -582,8 +582,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } CheckLintNameResult::NoLint(suggestion) => { let name = lint_name.clone(); - let suggestion = - suggestion.map(|replace| UnknownLintSuggestion::WithoutSpan { replace }); + let suggestion = suggestion.map(|(replace, from_rustc)| { + UnknownLintSuggestion::WithoutSpan { replace, from_rustc } + }); let requested_level = RequestedLevel { level, lint_name }; let lint = UnknownLintFromCommandLine { name, suggestion, requested_level }; self.emit_lint(UNKNOWN_LINTS, lint); @@ -990,8 +991,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } else { name.to_string() }; - let suggestion = suggestion.map(|replace| { - UnknownLintSuggestion::WithSpan { suggestion: sp, replace } + let suggestion = suggestion.map(|(replace, from_rustc)| { + UnknownLintSuggestion::WithSpan { suggestion: sp, replace, from_rustc } }); let lint = UnknownLint { name, suggestion }; self.emit_spanned_lint(UNKNOWN_LINTS, sp.into(), lint); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index bc9a9d7b7452d..f370c4392b384 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1050,9 +1050,10 @@ pub enum UnknownLintSuggestion { #[primary_span] suggestion: Span, replace: Symbol, + from_rustc: bool, }, #[help(lint_help)] - WithoutSpan { replace: Symbol }, + WithoutSpan { replace: Symbol, from_rustc: bool }, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 14cb1d6d362e2..87a0ccbb1a56d 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -170,6 +170,34 @@ pub fn find_best_match_for_name( find_best_match_for_name_impl(false, candidates, lookup, dist) } +/// Find the best match for multiple words +/// +/// This function is intended for use when the desired match would never be +/// returned due to a substring in `lookup` which is superfluous. +/// +/// For example, when looking for the closest lint name to `clippy:missing_docs`, +/// we would find `clippy::erasing_op`, despite `missing_docs` existing and being a better suggestion. +/// `missing_docs` would have a larger edit distance because it does not contain the `clippy` tool prefix. +/// In order to find `missing_docs`, this function takes multiple lookup strings, computes the best match +/// for each and returns the match which had the lowest edit distance. In our example, `clippy:missing_docs` and +/// `missing_docs` would be `lookups`, enabling `missing_docs` to be the best match, as desired. +pub fn find_best_match_for_names( + candidates: &[Symbol], + lookups: &[Symbol], + dist: Option, +) -> Option { + lookups + .iter() + .map(|s| (s, find_best_match_for_name_impl(false, candidates, *s, dist))) + .filter_map(|(s, r)| r.map(|r| (s, r))) + .min_by(|(s1, r1), (s2, r2)| { + let d1 = edit_distance(s1.as_str(), r1.as_str(), usize::MAX).unwrap(); + let d2 = edit_distance(s2.as_str(), r2.as_str(), usize::MAX).unwrap(); + d1.cmp(&d2) + }) + .map(|(_, r)| r) +} + #[cold] fn find_best_match_for_name_impl( use_substring_score: bool, diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed index cba32ce6b772a..c0ccd41c19ab6 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed @@ -7,10 +7,12 @@ #[warn(clippy::if_not_else)] #[warn(clippy::unnecessary_cast)] #[warn(clippy::useless_transmute)] -// Shouldn't suggest rustc lint name(`dead_code`) -#[warn(clippy::eq_op)] +// Should suggest rustc lint name(`dead_code`) +#[warn(dead_code)] // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`) #[warn(clippy::unused_self)] // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`) #[warn(clippy::redundant_static_lifetimes)] +// issue #118183, should report `missing_docs` from rustc lint +#[warn(missing_docs)] fn main() {} diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.rs b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs index c15d541974f00..7a59ad364aa7f 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.rs +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs @@ -7,10 +7,12 @@ #[warn(clippy::if_not_els)] #[warn(clippy::UNNecsaRy_cAst)] #[warn(clippy::useles_transute)] -// Shouldn't suggest rustc lint name(`dead_code`) +// Should suggest rustc lint name(`dead_code`) #[warn(clippy::dead_cod)] // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`) #[warn(clippy::unused_colle)] // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`) #[warn(clippy::const_static_lifetim)] +// issue #118183, should report `missing_docs` from rustc lint +#[warn(clippy::missing_docs)] fn main() {} diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr index ee82db31c2c2a..432c7f72e32ed 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr @@ -35,7 +35,12 @@ error: unknown lint: `clippy::dead_cod` --> $DIR/unknown_clippy_lints.rs:11:8 | LL | #[warn(clippy::dead_cod)] - | ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::eq_op` + | ^^^^^^^^^^^^^^^^ + | +help: a lint with a similar name exists in `rustc` lints + | +LL | #[warn(dead_code)] + | ~~~~~~~~~ error: unknown lint: `clippy::unused_colle` --> $DIR/unknown_clippy_lints.rs:13:8 @@ -49,5 +54,16 @@ error: unknown lint: `clippy::const_static_lifetim` LL | #[warn(clippy::const_static_lifetim)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::redundant_static_lifetimes` -error: aborting due to 8 previous errors +error: unknown lint: `clippy::missing_docs` + --> $DIR/unknown_clippy_lints.rs:17:8 + | +LL | #[warn(clippy::missing_docs)] + | ^^^^^^^^^^^^^^^^^^^^ + | +help: a lint with a similar name exists in `rustc` lints + | +LL | #[warn(missing_docs)] + | ~~~~~~~~~~~~ + +error: aborting due to 9 previous errors