Skip to content

add #![rustc_no_implicit_bounds] #142671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
TEST, rustc_insignificant_dtor, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes
),
rustc_attr!(
TEST, rustc_no_implicit_bounds, CrateLevel, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_strict_coherence, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes
Expand Down
20 changes: 11 additions & 9 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_hir::{AmbigArg, LangItem, PolyTraitRef};
use rustc_middle::bug;
use rustc_middle::ty::{
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor, Upcast,
};
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw};
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
use rustc_trait_selection::traits;
use smallvec::SmallVec;
use tracing::{debug, instrument};
Expand Down Expand Up @@ -188,6 +188,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) {
let tcx = self.tcx();

// Skip adding any default bounds if `#![rustc_no_implicit_bounds]`
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) {
return;
}

let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);

Expand Down Expand Up @@ -408,24 +413,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
let trait_id = tcx.lang_items().get(trait_);
if let Some(trait_id) = trait_id
&& self.do_not_provide_default_trait_bound(
trait_id,
hir_bounds,
self_ty_where_predicates,
)
&& self.should_add_default_traits(trait_id, hir_bounds, self_ty_where_predicates)
{
add_trait_bound(tcx, bounds, self_ty, trait_id, span);
}
}

fn do_not_provide_default_trait_bound<'a>(
/// Returns `true` if default trait bound should be added.
fn should_add_default_traits<'a>(
&self,
trait_def_id: DefId,
hir_bounds: &'a [hir::GenericBound<'tcx>],
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
) -> bool {
let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id);
!collected.any()
!self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any()
}

/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,7 @@ symbols! {
rustc_never_returns_null_ptr,
rustc_never_type_options,
rustc_no_implicit_autorefs,
rustc_no_implicit_bounds,
rustc_no_mir_inline,
rustc_nonnull_optimization_guaranteed,
rustc_nounwind,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
//@ compile-flags: -Znext-solver=coherence

#![feature(rustc_attrs)]
#![rustc_no_implicit_bounds]
#![recursion_limit = "10"]

trait Trait {}

struct W<T: ?Sized>(*const T);
struct W<T>(*const T);
trait TwoW {}
impl<T: ?Sized + TwoW> TwoW for W<W<T>> {}
impl<T: TwoW> TwoW for W<W<T>> {}

impl<T: ?Sized + TwoW> Trait for W<T> {}
impl<T: ?Sized + TwoW> Trait for T {}
impl<T: TwoW> Trait for W<T> {}
impl<T: TwoW> Trait for T {}
//~^ ERROR conflicting implementations of trait `Trait` for type `W

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/coherence-fulfill-overflow.rs:12:1
--> $DIR/coherence-fulfill-overflow.rs:14:1
|
LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
| ------------------------------------- first implementation here
LL | impl<T: ?Sized + TwoW> Trait for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
LL | impl<T: TwoW> Trait for W<T> {}
| ---------------------------- first implementation here
LL | impl<T: TwoW> Trait for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@ revisions: with without
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
#![rustc_no_implicit_bounds]

// This test is incredibly subtle. At its core the goal is to get a coinductive cycle,
// which, depending on its root goal, either holds or errors. We achieve this by getting
Expand All @@ -17,20 +18,20 @@
// test for that.

#[rustc_coinductive]
trait Trait<T: ?Sized, V: ?Sized, D: ?Sized> {}
struct A<T: ?Sized>(*const T);
struct B<T: ?Sized>(*const T);
trait Trait<T, V, D> {}
struct A<T>(*const T);
struct B<T>(*const T);

trait IncompleteGuidance<T: ?Sized, V: ?Sized> {}
impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, u8> for T {}
impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i8> for T {}
impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i16> for T {}
trait IncompleteGuidance<T, V> {}
impl<T, U: 'static> IncompleteGuidance<U, u8> for T {}
impl<T, U: 'static> IncompleteGuidance<U, i8> for T {}
impl<T, U: 'static> IncompleteGuidance<U, i16> for T {}

trait ImplGuidance<T: ?Sized, V: ?Sized> {}
impl<T: ?Sized> ImplGuidance<u32, u8> for T {}
impl<T: ?Sized> ImplGuidance<i32, i8> for T {}
trait ImplGuidance<T, V> {}
impl<T> ImplGuidance<u32, u8> for T {}
impl<T> ImplGuidance<i32, i8> for T {}

impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
impl<T, U, V, D> Trait<U, V, D> for A<T>
where
T: IncompleteGuidance<U, V>,
A<T>: Trait<U, D, V>,
Expand All @@ -39,17 +40,17 @@ where
{
}

trait ToU8<T: ?Sized> {}
trait ToU8<T> {}
impl ToU8<u8> for () {}

impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for B<T>
impl<T, U, V, D> Trait<U, V, D> for B<T>
where
T: ImplGuidance<U, V>,
A<T>: Trait<U, V, D>,
{
}

fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
fn impls_trait<T: Trait<U, V, D>, U, V, D>() {}

fn with_bound<X>()
where
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
--> $DIR/incompleteness-unstable-result.rs:65:19
--> $DIR/incompleteness-unstable-result.rs:66:19
|
LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`
|
= help: the trait `Trait<U, V, D>` is implemented for `A<T>`
note: required for `A<X>` to implement `Trait<_, _, _>`
--> $DIR/incompleteness-unstable-result.rs:33:50
--> $DIR/incompleteness-unstable-result.rs:34:18
|
LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
| ^^^^^^^^^^^^^^ ^^^^
LL | impl<T, U, V, D> Trait<U, V, D> for A<T>
| ^^^^^^^^^^^^^^ ^^^^
...
LL | A<T>: Trait<U, D, V>,
| -------------- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<_, _, _>`
note: required by a bound in `impls_trait`
--> $DIR/incompleteness-unstable-result.rs:52:28
--> $DIR/incompleteness-unstable-result.rs:53:19
|
LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
LL | fn impls_trait<T: Trait<U, V, D>, U, V, D>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait`

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
--> $DIR/incompleteness-unstable-result.rs:65:19
--> $DIR/incompleteness-unstable-result.rs:66:19
|
LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`
|
= help: the trait `Trait<U, V, D>` is implemented for `A<T>`
note: required for `A<X>` to implement `Trait<_, _, _>`
--> $DIR/incompleteness-unstable-result.rs:33:50
--> $DIR/incompleteness-unstable-result.rs:34:18
|
LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
| ^^^^^^^^^^^^^^ ^^^^
LL | impl<T, U, V, D> Trait<U, V, D> for A<T>
| ^^^^^^^^^^^^^^ ^^^^
...
LL | A<T>: Trait<U, D, V>,
| -------------- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<_, _, _>`
note: required by a bound in `impls_trait`
--> $DIR/incompleteness-unstable-result.rs:52:28
--> $DIR/incompleteness-unstable-result.rs:53:19
|
LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
LL | fn impls_trait<T: Trait<U, V, D>, U, V, D>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait`

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
#![rustc_no_implicit_bounds]

// Check that we correctly rerun the trait solver for heads of cycles,
// even if they are not the root.

struct A<T: ?Sized>(*const T);
struct B<T: ?Sized>(*const T);
struct C<T: ?Sized>(*const T);
struct A<T>(*const T);
struct B<T>(*const T);
struct C<T>(*const T);

#[rustc_coinductive]
trait Trait<'a, 'b> {}
trait NotImplemented {}

impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for A<T> where B<T>: Trait<'a, 'b> {}
impl<'a, 'b, T> Trait<'a, 'b> for A<T> where B<T>: Trait<'a, 'b> {}

// With this the root of `B<T>` is `A<T>`, even if the other impl does
// not have a cycle with `A<T>`. This candidate never applies because of
// the `A<T>: NotImplemented` bound.
impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for B<T>
impl<'a, 'b, T> Trait<'a, 'b> for B<T>
where
A<T>: Trait<'a, 'b>,
A<T>: NotImplemented,
Expand All @@ -31,7 +32,7 @@ where
// use the impl itself to prove that adds region constraints as we uniquified the
// regions in the `A<T>: Trait<'a, 'b>` where-bound. As both the impl above
// and the impl below now apply with some constraints, we failed with ambiguity.
impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for B<T>
impl<'a, 'b, T> Trait<'a, 'b> for B<T>
where
A<T>: NotImplemented,
{}
Expand All @@ -40,22 +41,22 @@ where
//
// Because of the coinductive cycle through `C<T>` it also requires
// 'a to be 'static.
impl<'a, T: ?Sized> Trait<'a, 'static> for B<T>
impl<'a, T> Trait<'a, 'static> for B<T>
where
C<T>: Trait<'a, 'a>,
{}

// In the first iteration of `B<T>: Trait<'a, 'b>` we don't add any
// constraints here, only after setting the provisional result to require
// `'b == 'static` do we also add that constraint for `'a`.
impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for C<T>
impl<'a, 'b, T> Trait<'a, 'b> for C<T>
where
B<T>: Trait<'a, 'b>,
{}

fn impls_trait<'a, 'b, T: Trait<'a, 'b> + ?Sized>() {}
fn impls_trait<'a, 'b, T: Trait<'a, 'b>>() {}

fn check<'a, T: ?Sized>() {
fn check<'a, T>() {
impls_trait::<'a, 'static, A<T>>();
//~^ ERROR lifetime may not live long enough
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
error: lifetime may not live long enough
--> $DIR/fixpoint-rerun-all-cycle-heads.rs:59:5
--> $DIR/fixpoint-rerun-all-cycle-heads.rs:60:5
|
LL | fn check<'a, T: ?Sized>() {
LL | fn check<'a, T>() {
| -- lifetime `'a` defined here
LL | impls_trait::<'a, 'static, A<T>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
Expand Down
6 changes: 4 additions & 2 deletions tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
#![rustc_no_implicit_bounds]

// This currently hangs if we do not erase constraints from
// overflow.
Expand All @@ -17,9 +19,9 @@
// the solver to hang without hitting the recursion limit.
trait Trait {}

struct W<T: ?Sized>(*const T);
struct W<T>(*const T);

impl<T: ?Sized> Trait for W<W<T>>
impl<T> Trait for W<W<T>>
where
W<T>: Trait,
W<T>: Trait,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0275]: overflow evaluating the requirement `W<_>: Trait`
--> $DIR/inductive-fixpoint-hang.rs:31:19
--> $DIR/inductive-fixpoint-hang.rs:33:19
|
LL | impls_trait::<W<_>>();
| ^^^^
|
note: required by a bound in `impls_trait`
--> $DIR/inductive-fixpoint-hang.rs:28:19
--> $DIR/inductive-fixpoint-hang.rs:30:19
|
LL | fn impls_trait<T: Trait>() {}
| ^^^^^ required by this bound in `impls_trait`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@ compile-flags: -Znext-solver
//@ check-pass
#![feature(rustc_attrs)]
#![rustc_no_implicit_bounds]

// A test showcasing that using a provisional cache can differ
// from only tracking stack entries.
Expand Down Expand Up @@ -59,9 +60,9 @@ trait B {}
#[rustc_coinductive]
trait C {}

impl<T: ?Sized + B + C> A for T {}
impl<T: ?Sized + A + C> B for T {}
impl<T: ?Sized + B> C for T {}
impl<T: B + C> A for T {}
impl<T: A + C> B for T {}
impl<T: B> C for T {}

fn impls_a<T: A>() {}

Expand Down
8 changes: 5 additions & 3 deletions tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//@ compile-flags: -Znext-solver
#![feature(rustc_attrs)]
#![rustc_no_implicit_bounds]

trait Tr<'a> {}

Expand All @@ -16,9 +18,9 @@ trait Tr<'a> {}
// Then, when we recompute the goal `W<?0>: Constrain<'error>`, when
// collecting ambiguities and overflows, we end up assembling a default
// error candidate w/o ambiguity, which causes the goal to pass, and ICE.
impl<'a, A: ?Sized> Tr<'a> for W<A> {}
struct W<A: ?Sized>(A);
impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {}
impl<'a, A> Tr<'a> for W<A> {}
struct W<A>(A);
impl<'a, A> Tr<'a> for A where A: Constrain<'a> {}
//~^ ERROR conflicting implementations of trait `Tr<'_>` for type `W<_>`

trait Constrain<'a> {}
Expand Down
Loading
Loading