Skip to content
6 changes: 2 additions & 4 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

pub(super) fn report_ambiguous_assoc_item(
&self,
bound1: ty::PolyTraitRef<'tcx>,
bound2: ty::PolyTraitRef<'tcx>,
matching_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
matching_candidates: &[ty::PolyTraitRef<'tcx>],
qself: AssocItemQSelf,
assoc_tag: ty::AssocTag,
assoc_ident: Ident,
Expand Down Expand Up @@ -443,7 +441,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// predicates!).
// FIXME: Turn this into a structured, translatable & more actionable suggestion.
let mut where_bounds = vec![];
for bound in [bound1, bound2].into_iter().chain(matching_candidates) {
for &bound in matching_candidates {
let bound_id = bound.def_id();
let assoc_item = tcx.associated_items(bound_id).find_by_ident_and_kind(
tcx,
Expand Down
80 changes: 77 additions & 3 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::{assert_matches, slice};
use rustc_abi::FIRST_VARIANT;
use rustc_ast::LitKind;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::sso::SsoHashSet;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, StashKey,
Expand Down Expand Up @@ -1262,6 +1263,74 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
}

/// When there are multiple traits which contain an identically named
/// associated item, this function eliminates any traits which are a
/// supertrait of another candidate trait.
///
/// This is the type-level analogue of
/// `rustc_hir_typeck::method::probe::ProbeContext::collapse_candidates_to_subtrait_pick`;
/// keep both implementations in sync.
///
/// This implements RFC #3624.
fn collapse_candidates_to_subtrait_pick(
&self,
matching_candidates: &[ty::PolyTraitRef<'tcx>],
) -> Option<ty::PolyTraitRef<'tcx>> {
if !self.tcx().features().supertrait_item_shadowing() {
return None;
}

let mut child_trait = matching_candidates[0];
let mut supertraits: SsoHashSet<_> =
traits::supertrait_def_ids(self.tcx(), child_trait.def_id()).collect();

let mut remaining_candidates: Vec<_> = matching_candidates[1..].iter().copied().collect();
while !remaining_candidates.is_empty() {
let mut made_progress = false;
let mut next_round = vec![];

for remaining_trait in remaining_candidates {
if supertraits.contains(&remaining_trait.def_id()) {
made_progress = true;
continue;
}

// This candidate is not a supertrait of the `child_trait`.
// Check if it's a subtrait of the `child_trait`, instead.
// If it is, then it must have been a subtrait of every
// other pick we've eliminated at this point. It will
// take over at this point.
let remaining_trait_supertraits: SsoHashSet<_> =
traits::supertrait_def_ids(self.tcx(), remaining_trait.def_id()).collect();
if remaining_trait_supertraits.contains(&child_trait.def_id()) {
child_trait = remaining_trait;
supertraits = remaining_trait_supertraits;
made_progress = true;
continue;
}

// Neither `child_trait` or the current candidate are
// supertraits of each other.
// Don't bail here, since we may be comparing two supertraits
// of a common subtrait. These two supertraits won't be related
// at all, but we will pick them up next round when we find their
// child as we continue iterating in this round.
next_round.push(remaining_trait);
}

if made_progress {
// If we've made progress, iterate again.
remaining_candidates = next_round;
} else {
// Otherwise, we must have at least two candidates which
// are not related to each other at all.
return None;
}
}

Some(child_trait)
}

/// Search for a single trait bound whose trait defines the associated item given by
/// `assoc_ident`.
///
Expand Down Expand Up @@ -1296,10 +1365,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};

if let Some(bound2) = matching_candidates.next() {
let all_matching_candidates: Vec<_> =
[bound1, bound2].into_iter().chain(matching_candidates).collect();
if let Some(bound) = self.collapse_candidates_to_subtrait_pick(&all_matching_candidates)
{
return Ok(bound);
}

return Err(self.report_ambiguous_assoc_item(
bound1,
bound2,
matching_candidates,
&all_matching_candidates,
qself,
assoc_tag,
assoc_ident,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2359,6 +2359,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// multiple conflicting picks if there is one pick whose trait container is a subtrait
/// of the trait containers of all of the other picks.
///
/// This is the method-probe analogue of
/// `rustc_hir_analysis::hir_ty_lowering::HirTyLowerer::collapse_candidates_to_subtrait_pick`;
/// keep both implementations in sync.
///
/// This implements RFC #3624.
fn collapse_candidates_to_subtrait_pick(
&self,
Expand Down
250 changes: 250 additions & 0 deletions library/std/src/attribute_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,253 @@
/// [`unused_must_use`]: ../rustc/lints/listing/warn-by-default.html#unused-must-use
/// [the `must_use` attribute]: ../reference/attributes/diagnostics.html#the-must_use-attribute
mod must_use_attribute {}

#[doc(attribute = "allow")]
//
/// The `allow` attribute suppresses lint diagnostics that would otherwise produce
/// warnings or errors. It can be used on any lint or lint group (except those
/// set to `forbid`).
///
/// ```rust
/// #[allow(dead_code)]
/// fn unused_function() {
/// // ...
/// }
///
/// fn main() {
/// // `unused_function` does not generate a compiler warning.
/// }
/// ```
///
/// Without `#[allow(dead_code)]`, the example above would emit:
///
/// ```text
/// warning: function `unused_function` is never used
/// --> main.rs:1:4
/// |
/// 1 | fn unused_function() {
/// | ^^^^^^^^^^^^^^^
/// |
/// = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
///
/// warning: 1 warning emitted
/// ```
///
/// Multiple lints can be set to `allow` at once with commas:
///
/// ```rust
/// #[allow(unused_variables, unused_mut)]
/// fn main() {
/// let mut x: u32 = 42;
/// }
/// ```
///
/// This is mostly used to prevent lint warnings or errors while still under development.
///
/// It cannot override a lint that has been set to `forbid`.
///
/// It's also important to consider that overusing `allow` could make code harder to maintain
/// and possibly hide issues. To mitigate this issue, using the `expect` attribute is preferred.
///
/// `allow` can be overridden by `warn`, `deny`, and `forbid`.
///
/// The lint checks supported by rustc can be found via `rustc -W help`,
/// along with their default settings and are documented in [the `rustc` book].
///
/// [the `rustc` book]: ../rustc/lints/listing/index.html
///
/// For more information, see the Reference on [the `allow` attribute].
///
/// [the `allow` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
mod allow_attribute {}

#[doc(attribute = "cfg")]
//
/// Used for conditional compilation.
///
/// The `cfg` attribute allows compiling an item under specific conditions, otherwise it
/// will be ignored.
///
/// ```rust
/// // Only compiles this function for Linux.
/// #[cfg(target_os = "linux")]
/// fn platform_specific() {
/// println!("Running on Linux");
/// }
///
/// // Only compiles this function if not for Linux.
/// #[cfg(not(target_os = "linux"))]
/// fn platform_specific() {
/// println!("Running on something else");
/// }
/// ```
///
/// Depending on the platform you're targeting, only one of these two functions will be considered
/// during the compilation.
///
/// Conditions can also be combined with `all(...)`, `any(...)`, and `not(...)`.
///
/// * `all`: True if all given predicates are true.
/// * `any`: True if at least one of the given predicates is true.
/// * `not`: True if the predicate is false and false if the predicate is true.
///
/// ```rust
/// #[cfg(all(unix, target_pointer_width = "64"))]
/// fn unix_64bit() {
/// }
/// ```
///
/// If you want to use this mechanism in an `if` condition in your code, you
/// can use the [`cfg!`] macro. To conditionally apply an attribute,
/// see [`cfg_attr`].
///
/// For more information, see the Reference on [the `cfg` attribute].
///
/// [`cfg_attr`]: ../reference/conditional-compilation.html#the-cfg_attr-attribute
/// [the `cfg` attribute]: ../reference/conditional-compilation.html#the-cfg-attribute
mod cfg_attribute {}

#[doc(attribute = "deny")]
//
/// Emits an error, preventing the compilation from finishing, when a lint check has failed.
/// This is useful for enforcing rules or preventing certain patterns:
///
/// ```rust,compile_fail
/// #[deny(unused)]
/// fn foo() {
/// let x = 42; // Emits an error because x is unused.
/// }
/// ```
///
/// `deny` can be overridden by `allow`, `warn`, and `forbid`:
///
/// ```rust
/// #![deny(unused)]
///
/// #[allow(unused)] // We override the `deny` for this function.
/// fn foo() {
/// let x = 42; // No lint emitted even though `x` is unused.
/// }
/// ```
///
/// Multiple lints can also be set to `deny` at once:
///
/// ```rust,compile_fail
/// #![deny(unused_imports, unused_variables)]
/// use std::collections::*;
///
/// fn main() {
/// let mut x = 10;
/// }
/// ```
///
/// The lint checks supported by rustc can be found via `rustc -W help`,
/// along with their default settings and are documented in [the `rustc` book].
///
/// [the `rustc` book]: ../rustc/lints/listing/index.html
///
/// For more information, see the Reference on [the `deny` attribute].
///
/// [the `deny` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
mod deny_attribute {}

#[doc(attribute = "forbid")]
//
/// Emits an error, preventing the compilation from finishing, when a lint check has failed.
///
/// A lint set to `forbid` cannot be overridden by `allow` or `warn`.
/// Attempting either will result in a compilation error. Writing `#[deny(...)]` on the same lint inside a
/// `forbid` scope is permitted, but has no effect; the lint remains at the `forbid` level.
///
/// This is useful for enforcing strict policies that should not be relaxed
/// anywhere in the codebase. Example:
///
/// ```rust
/// #![forbid(unsafe_code)]
///
/// // This would cause a compilation error if uncommented:
/// // #[allow(unsafe_code)] // error: cannot override `forbid`
/// ```
///
/// Multiple lints can be set to `forbid` at once:
///
/// ```rust
/// #![forbid(unsafe_code, unused)]
/// ```
///
/// The lint checks supported by rustc can be found via `rustc -W help`,
/// along with their default settings and are documented in [the `rustc` book].
///
/// [the `rustc` book]: ../rustc/lints/listing/index.html
///
/// For more information, see the Reference on [the `forbid` attribute].
///
/// [the `forbid` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
mod forbid_attribute {}

#[doc(attribute = "deprecated")]
//
/// Emits a warning during compilation when an item with this attribute is used.
/// `since` and `note` are optional fields giving more detail about why the item is deprecated.
///
/// * `since`: the version since when the item is deprecated.
/// * `note`: the reason why an item is deprecated.
///
/// Example:
///
/// ```rust
/// #[deprecated(since = "1.0.0", note = "Use bar instead")]
/// struct Foo;
/// struct Bar;
/// ```
///
/// `deprecated` attribute helps developers transition away from old code by providing warnings when
/// deprecated items are used. Note that during `Cargo` builds, warnings on dependencies get silenced
/// by default, so you may not see a deprecation warning unless you build that dependency directly.
///
/// For more information, see the Reference on [the `deprecated` attribute].
///
/// [the `deprecated` attribute]: ../reference/attributes/diagnostics.html#the-deprecated-attribute
mod deprecated_attribute {}

#[doc(attribute = "warn")]
//
/// Emits a warning during compilation when a lint check failed.
///
/// Unlike `deny` or `forbid`, `warn` does not produce a hard error: the compilation continues, but
/// the compiler emits a warning message. `warn` can be overridden by `allow`, `deny`, and `forbid`.
///
/// Example:
///
/// ```rust,compile_fail
/// #![allow(unused)]
///
/// #[warn(unused)] // We override the allowed `unused` lint.
/// fn foo() {
/// // This lint warns by default even without #[warn(unused)] being explicitly set
/// let x = 42; // warning: unused variable `x`
/// }
/// ```
///
///
/// Many lints, including `unused`, are already set to `warn` by default so this attribute is
/// mainly useful for lints that are normally `allow` by default.
///
/// Multiple lints can be set to `warn` at once:
///
/// ```rust,compile_fail
/// #[warn(unused_mut, unused_variables)]
/// fn main() {
/// let mut x = 42;
/// }
/// ```
///
/// The lint checks supported by rustc can be found via `rustc -W help`,
/// along with their default settings and are documented in [the `rustc` book].
///
/// [the `rustc` book]: ../rustc/lints/listing/index.html
///
/// For more information, see the Reference on [the `warn` attribute].
///
/// [the `warn` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes
mod warn_attribute {}
Loading
Loading