Auto merge of #102139 - Dylan-DPC:rollup-ljlipt8, r=Dylan-DPC

Rollup of 8 pull requests

Successful merges:

 - #101598 (Update rustc's information on Android's sanitizers)
 - #102036 (Remove use of `io::ErrorKind::Other` in std)
 - #102037 (Make cycle errors recoverable)
 - #102069 (Skip `Equate` relation in `handle_opaque_type`)
 - #102076 (rustc_transmute: fix big-endian discriminants)
 - #102107 (Add missing space between notable trait tooltip and where clause)
 - #102119 (Fix a typo “pararmeter” in error message)
 - #102131 (Added which number is computed in compute_float.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-09-22 15:18:35 +00:00
commit 89e4e1f1b3
26 changed files with 126 additions and 63 deletions

View file

@ -1090,11 +1090,12 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
// both executables and dynamic shared objects. Everywhere else the runtimes // both executables and dynamic shared objects. Everywhere else the runtimes
// are currently distributed as static libraries which should be linked to // are currently distributed as static libraries which should be linked to
// executables only. // executables only.
let needs_runtime = match crate_type { let needs_runtime = !sess.target.is_like_android
CrateType::Executable => true, && match crate_type {
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx, CrateType::Executable => true,
CrateType::Rlib | CrateType::Staticlib => false, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
}; CrateType::Rlib | CrateType::Staticlib => false,
};
if !needs_runtime { if !needs_runtime {
return; return;

View file

@ -95,6 +95,10 @@ pub trait ForestObligation: Clone + Debug {
pub trait ObligationProcessor { pub trait ObligationProcessor {
type Obligation: ForestObligation; type Obligation: ForestObligation;
type Error: Debug; type Error: Debug;
type OUT: OutcomeTrait<
Obligation = Self::Obligation,
Error = Error<Self::Obligation, Self::Error>,
>;
fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool; fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool;
@ -111,7 +115,11 @@ pub trait ObligationProcessor {
/// In other words, if we had O1 which required O2 which required /// In other words, if we had O1 which required O2 which required
/// O3 which required O1, we would give an iterator yielding O1, /// O3 which required O1, we would give an iterator yielding O1,
/// O2, O3 (O1 is not yielded twice). /// O2, O3 (O1 is not yielded twice).
fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::Obligation>) fn process_backedge<'c, I>(
&mut self,
cycle: I,
_marker: PhantomData<&'c Self::Obligation>,
) -> Result<(), Self::Error>
where where
I: Clone + Iterator<Item = &'c Self::Obligation>; I: Clone + Iterator<Item = &'c Self::Obligation>;
} }
@ -402,12 +410,11 @@ impl<O: ForestObligation> ObligationForest<O> {
/// Performs a fixpoint computation over the obligation list. /// Performs a fixpoint computation over the obligation list.
#[inline(never)] #[inline(never)]
pub fn process_obligations<P, OUT>(&mut self, processor: &mut P) -> OUT pub fn process_obligations<P>(&mut self, processor: &mut P) -> P::OUT
where where
P: ObligationProcessor<Obligation = O>, P: ObligationProcessor<Obligation = O>,
OUT: OutcomeTrait<Obligation = O, Error = Error<O, P::Error>>,
{ {
let mut outcome = OUT::new(); let mut outcome = P::OUT::new();
// Fixpoint computation: we repeat until the inner loop stalls. // Fixpoint computation: we repeat until the inner loop stalls.
loop { loop {
@ -473,7 +480,7 @@ impl<O: ForestObligation> ObligationForest<O> {
} }
self.mark_successes(); self.mark_successes();
self.process_cycles(processor); self.process_cycles(processor, &mut outcome);
self.compress(|obl| outcome.record_completed(obl)); self.compress(|obl| outcome.record_completed(obl));
} }
@ -558,7 +565,7 @@ impl<O: ForestObligation> ObligationForest<O> {
/// Report cycles between all `Success` nodes, and convert all `Success` /// Report cycles between all `Success` nodes, and convert all `Success`
/// nodes to `Done`. This must be called after `mark_successes`. /// nodes to `Done`. This must be called after `mark_successes`.
fn process_cycles<P>(&mut self, processor: &mut P) fn process_cycles<P>(&mut self, processor: &mut P, outcome: &mut P::OUT)
where where
P: ObligationProcessor<Obligation = O>, P: ObligationProcessor<Obligation = O>,
{ {
@ -568,7 +575,7 @@ impl<O: ForestObligation> ObligationForest<O> {
// to handle the no-op cases immediately to avoid the cost of the // to handle the no-op cases immediately to avoid the cost of the
// function call. // function call.
if node.state.get() == NodeState::Success { if node.state.get() == NodeState::Success {
self.find_cycles_from_node(&mut stack, processor, index); self.find_cycles_from_node(&mut stack, processor, index, outcome);
} }
} }
@ -576,8 +583,13 @@ impl<O: ForestObligation> ObligationForest<O> {
self.reused_node_vec = stack; self.reused_node_vec = stack;
} }
fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize) fn find_cycles_from_node<P>(
where &self,
stack: &mut Vec<usize>,
processor: &mut P,
index: usize,
outcome: &mut P::OUT,
) where
P: ObligationProcessor<Obligation = O>, P: ObligationProcessor<Obligation = O>,
{ {
let node = &self.nodes[index]; let node = &self.nodes[index];
@ -586,17 +598,20 @@ impl<O: ForestObligation> ObligationForest<O> {
None => { None => {
stack.push(index); stack.push(index);
for &dep_index in node.dependents.iter() { for &dep_index in node.dependents.iter() {
self.find_cycles_from_node(stack, processor, dep_index); self.find_cycles_from_node(stack, processor, dep_index, outcome);
} }
stack.pop(); stack.pop();
node.state.set(NodeState::Done); node.state.set(NodeState::Done);
} }
Some(rpos) => { Some(rpos) => {
// Cycle detected. // Cycle detected.
processor.process_backedge( let result = processor.process_backedge(
stack[rpos..].iter().map(|&i| &self.nodes[i].obligation), stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
PhantomData, PhantomData,
); );
if let Err(err) = result {
outcome.record_error(Error { error: err, backtrace: self.error_at(index) });
}
} }
} }
} }

View file

@ -64,6 +64,7 @@ where
{ {
type Obligation = O; type Obligation = O;
type Error = E; type Error = E;
type OUT = TestOutcome<O, E>;
fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool { fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool {
true true
@ -76,10 +77,15 @@ where
(self.process_obligation)(obligation) (self.process_obligation)(obligation)
} }
fn process_backedge<'c, I>(&mut self, _cycle: I, _marker: PhantomData<&'c Self::Obligation>) fn process_backedge<'c, I>(
&mut self,
_cycle: I,
_marker: PhantomData<&'c Self::Obligation>,
) -> Result<(), Self::Error>
where where
I: Clone + Iterator<Item = &'c Self::Obligation>, I: Clone + Iterator<Item = &'c Self::Obligation>,
{ {
Ok(())
} }
} }

View file

@ -7,6 +7,7 @@ use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{ use rustc_middle::ty::{
@ -176,16 +177,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} else if let Some(res) = process(b, a) { } else if let Some(res) = process(b, a) {
res res
} else { } else {
// Rerun equality check, but this time error out due to let (a, b) = self.resolve_vars_if_possible((a, b));
// different types. Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
Ok(_) => span_bug!(
cause.span,
"opaque types are never equal to anything but themselves: {:#?}",
(a.kind(), b.kind())
),
Err(e) => Err(e),
}
} }
} }

View file

@ -113,6 +113,8 @@ pub struct FulfillmentError<'tcx> {
#[derive(Clone)] #[derive(Clone)]
pub enum FulfillmentErrorCode<'tcx> { pub enum FulfillmentErrorCode<'tcx> {
/// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
CodeCycle(Vec<Obligation<'tcx, ty::Predicate<'tcx>>>),
CodeSelectionError(SelectionError<'tcx>), CodeSelectionError(SelectionError<'tcx>),
CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>),
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate

View file

@ -47,6 +47,7 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
write!(f, "CodeConstEquateError({:?}, {:?})", a, b) write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
} }
super::CodeAmbiguity => write!(f, "Ambiguity"), super::CodeAmbiguity => write!(f, "Ambiguity"),
super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle),
} }
} }
} }

View file

@ -173,7 +173,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
span, span,
span_label: match res { span_label: match res {
Res::Def(kind, def_id) if kind == DefKind::TyParam => { Res::Def(kind, def_id) if kind == DefKind::TyParam => {
self.def_span(def_id).map(|span| (span, "found this type pararmeter")) self.def_span(def_id).map(|span| (span, "found this type parameter"))
} }
_ => None, _ => None,
}, },

View file

@ -1,10 +1,12 @@
use crate::spec::TargetOptions; use crate::spec::{SanitizerSet, TargetOptions};
pub fn opts() -> TargetOptions { pub fn opts() -> TargetOptions {
let mut base = super::linux_base::opts(); let mut base = super::linux_base::opts();
base.os = "android".into(); base.os = "android".into();
base.is_like_android = true;
base.default_dwarf_version = 2; base.default_dwarf_version = 2;
base.has_thread_local = false; base.has_thread_local = false;
base.supported_sanitizers = SanitizerSet::ADDRESS;
// This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867 // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
// for context. (At that time, there was no `-C force-unwind-tables`, so the only solution // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
// was to always emit `uwtable`). // was to always emit `uwtable`).

View file

@ -1,9 +1,10 @@
use crate::spec::{LinkerFlavor, StackProbeType, Target}; use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target { pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts(); let mut base = super::linux_gnu_base::opts();
base.cpu = "pentium4".into(); base.cpu = "pentium4".into();
base.max_atomic_width = Some(64); base.max_atomic_width = Some(64);
base.supported_sanitizers = SanitizerSet::ADDRESS;
base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call; base.stack_probes = StackProbeType::Call;

View file

@ -1381,6 +1381,8 @@ pub struct TargetOptions {
pub is_like_msvc: bool, pub is_like_msvc: bool,
/// Whether a target toolchain is like WASM. /// Whether a target toolchain is like WASM.
pub is_like_wasm: bool, pub is_like_wasm: bool,
/// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc
pub is_like_android: bool,
/// Default supported version of DWARF on this platform. /// Default supported version of DWARF on this platform.
/// Useful because some platforms (osx, bsd) only want up to DWARF2. /// Useful because some platforms (osx, bsd) only want up to DWARF2.
pub default_dwarf_version: u32, pub default_dwarf_version: u32,
@ -1673,6 +1675,7 @@ impl Default for TargetOptions {
is_like_windows: false, is_like_windows: false,
is_like_msvc: false, is_like_msvc: false,
is_like_wasm: false, is_like_wasm: false,
is_like_android: false,
default_dwarf_version: 4, default_dwarf_version: 4,
allows_weak_linkage: true, allows_weak_linkage: true,
has_rpath: false, has_rpath: false,
@ -2320,6 +2323,7 @@ impl Target {
key!(is_like_windows, bool); key!(is_like_windows, bool);
key!(is_like_msvc, bool); key!(is_like_msvc, bool);
key!(is_like_wasm, bool); key!(is_like_wasm, bool);
key!(is_like_android, bool);
key!(default_dwarf_version, u32); key!(default_dwarf_version, u32);
key!(allows_weak_linkage, bool); key!(allows_weak_linkage, bool);
key!(has_rpath, bool); key!(has_rpath, bool);
@ -2570,6 +2574,7 @@ impl ToJson for Target {
target_option_val!(is_like_windows); target_option_val!(is_like_windows);
target_option_val!(is_like_msvc); target_option_val!(is_like_msvc);
target_option_val!(is_like_wasm); target_option_val!(is_like_wasm);
target_option_val!(is_like_android);
target_option_val!(default_dwarf_version); target_option_val!(default_dwarf_version);
target_option_val!(allows_weak_linkage); target_option_val!(allows_weak_linkage);
target_option_val!(has_rpath); target_option_val!(has_rpath);

View file

@ -4,10 +4,12 @@
// general routines. // general routines.
use crate::infer::{DefiningAnchor, TyCtxtInferExt}; use crate::infer::{DefiningAnchor, TyCtxtInferExt};
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::{ use crate::traits::{
ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
Unimplemented, Unimplemented,
}; };
use rustc_infer::traits::FulfillmentErrorCode;
use rustc_middle::traits::CodegenObligationError; use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
@ -62,6 +64,14 @@ pub fn codegen_select_candidate<'tcx>(
// optimization to stop iterating early. // optimization to stop iterating early.
let errors = fulfill_cx.select_all_or_error(&infcx); let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() { if !errors.is_empty() {
// `rustc_monomorphize::collector` assumes there are no type errors.
// Cycle errors are the only post-monomorphization errors possible; emit them now so
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
for err in errors {
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
infcx.report_overflow_error_cycle(&cycle);
}
}
return Err(CodegenObligationError::FulfillmentError); return Err(CodegenObligationError::FulfillmentError);
} }

View file

@ -1540,6 +1540,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
} }
diag.emit(); diag.emit();
} }
FulfillmentErrorCode::CodeCycle(ref cycle) => {
self.report_overflow_error_cycle(cycle);
}
} }
} }

View file

@ -25,10 +25,9 @@ use super::Unimplemented;
use super::{FulfillmentError, FulfillmentErrorCode}; use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation}; use super::{ObligationCause, PredicateObligation};
use crate::traits::error_reporting::InferCtxtExt as _;
use crate::traits::project::PolyProjectionObligation; use crate::traits::project::PolyProjectionObligation;
use crate::traits::project::ProjectionCacheKeyExt as _; use crate::traits::project::ProjectionCacheKeyExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
/// Note that we include both the `ParamEnv` and the `Predicate`, /// Note that we include both the `ParamEnv` and the `Predicate`,
@ -224,6 +223,7 @@ fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligatio
impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
type Obligation = PendingPredicateObligation<'tcx>; type Obligation = PendingPredicateObligation<'tcx>;
type Error = FulfillmentErrorCode<'tcx>; type Error = FulfillmentErrorCode<'tcx>;
type OUT = Outcome<Self::Obligation, Self::Error>;
/// Identifies whether a predicate obligation needs processing. /// Identifies whether a predicate obligation needs processing.
/// ///
@ -594,14 +594,16 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
&mut self, &mut self,
cycle: I, cycle: I,
_marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
) where ) -> Result<(), FulfillmentErrorCode<'tcx>>
where
I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>, I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
{ {
if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
debug!("process_child_obligations: coinductive match"); debug!("process_child_obligations: coinductive match");
Ok(())
} else { } else {
let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
self.selcx.infcx().report_overflow_error_cycle(&cycle); Err(FulfillmentErrorCode::CodeCycle(cycle))
} }
} }
} }

View file

@ -226,13 +226,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext { SelectionContext { intercrate: true, ..SelectionContext::new(infcx) }
infcx,
freshener: infcx.freshener_keep_static(),
intercrate: true,
intercrate_ambiguity_causes: None,
query_mode: TraitQueryMode::Standard,
}
} }
pub fn with_query_mode( pub fn with_query_mode(
@ -240,13 +234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
query_mode: TraitQueryMode, query_mode: TraitQueryMode,
) -> SelectionContext<'cx, 'tcx> { ) -> SelectionContext<'cx, 'tcx> {
debug!(?query_mode, "with_query_mode"); debug!(?query_mode, "with_query_mode");
SelectionContext { SelectionContext { query_mode, ..SelectionContext::new(infcx) }
infcx,
freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
query_mode,
}
} }
/// Enables tracking of intercrate ambiguity causes. See /// Enables tracking of intercrate ambiguity causes. See

View file

@ -404,7 +404,7 @@ pub(crate) mod rustc {
.unwrap(); .unwrap();
trace!(?discr_layout, "computed discriminant layout"); trace!(?discr_layout, "computed discriminant layout");
variant_layout = variant_layout.extend(discr_layout).unwrap().0; variant_layout = variant_layout.extend(discr_layout).unwrap().0;
tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size)); tree = tree.then(Self::from_discr(discr, tcx, layout_summary.discriminant_size));
} }
// Next come fields. // Next come fields.
@ -444,11 +444,21 @@ pub(crate) mod rustc {
Ok(tree) Ok(tree)
} }
pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self { pub fn from_discr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
// FIXME(@jswrenn): I'm certain this is missing needed endian nuance. use rustc_target::abi::Endian;
let bytes = discr.val.to_ne_bytes();
let bytes = &bytes[..size]; let bytes: [u8; 16];
Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect()) let bytes = match tcx.data_layout.endian {
Endian::Little => {
bytes = discr.val.to_le_bytes();
&bytes[..size]
}
Endian::Big => {
bytes = discr.val.to_be_bytes();
&bytes[bytes.len() - size..]
}
};
Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect())
} }
} }

View file

@ -6,7 +6,7 @@ use crate::num::dec2flt::table::{
LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE, LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE,
}; };
/// Compute a float using an extended-precision representation. /// Compute w * 10^q using an extended-precision float representation.
/// ///
/// Fast conversion of a the significant digits and decimal exponent /// Fast conversion of a the significant digits and decimal exponent
/// a float to an extended representation with a binary float. This /// a float to an extended representation with a binary float. This

View file

@ -822,14 +822,14 @@ impl crate::os::linux::process::ChildExt for crate::process::Child {
self.handle self.handle
.pidfd .pidfd
.as_ref() .as_ref()
.ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created.")) .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created."))
} }
fn take_pidfd(&mut self) -> io::Result<PidFd> { fn take_pidfd(&mut self) -> io::Result<PidFd> {
self.handle self.handle
.pidfd .pidfd
.take() .take()
.ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created.")) .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created."))
} }
} }

View file

@ -371,7 +371,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
format!("<br><span class=\"where\">where{where_preds}</span>") format!("<br><span class=\"where\">where{where_preds}</span>")
} else { } else {
let mut clause = br_with_padding; let mut clause = br_with_padding;
clause.truncate(clause.len() - 5 * "&nbsp;".len()); clause.truncate(clause.len() - 4 * "&nbsp;".len());
write!(clause, "<span class=\"where\">where{where_preds}</span>")?; write!(clause, "<span class=\"where\">where{where_preds}</span>")?;
clause clause
} }

View file

@ -1,4 +1,5 @@
// check-pass // check-pass
// compile-flags: -Znormalize-docs
// Regression test for <https://github.com/rust-lang/rust/issues/79459>. // Regression test for <https://github.com/rust-lang/rust/issues/79459>.
pub trait Query {} pub trait Query {}

View file

@ -1,3 +1,8 @@
<div class="item-decl"><pre class="rust trait"><code>pub trait TraitWhere { <div class="item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160;<span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: 'a</span>; type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160;&#160;<span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: 'a</span>;
fn <a href="#method.func" class="fnname">func</a>(self)<br />&#160;&#160;&#160;&#160;<span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span>,
{ ... }
<span class="item-spacer" /> fn <a href="#method.lines" class="fnname">lines</a>(self) -&gt; <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a>&lt;Self&gt;<br />&#160;&#160;&#160;&#160;<span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span>,
{ ... }
}</code></pre></div> }</code></pre></div>

View file

@ -1,5 +1,7 @@
#![crate_name = "foo"] #![crate_name = "foo"]
use std::io::Lines;
pub trait MyTrait { fn dummy(&self) { } } pub trait MyTrait { fn dummy(&self) { } }
// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait" // @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait"
@ -29,6 +31,16 @@ where
// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="item-decl"]' // @snapshot SWhere_TraitWhere_item-decl - '//div[@class="item-decl"]'
pub trait TraitWhere { pub trait TraitWhere {
type Item<'a> where Self: 'a; type Item<'a> where Self: 'a;
fn func(self)
where
Self: Sized
{}
fn lines(self) -> Lines<Self>
where
Self: Sized,
{ todo!() }
} }
// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \

View file

@ -4,7 +4,7 @@ error[E0423]: expected value, found type parameter `T`
LL | impl<T> Bar<T> for [u8; T] {} LL | impl<T> Bar<T> for [u8; T] {}
| - ^ not a value | - ^ not a value
| | | |
| found this type pararmeter | found this type parameter
error[E0599]: the function or associated item `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied error[E0599]: the function or associated item `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied
--> $DIR/issue-69654.rs:17:10 --> $DIR/issue-69654.rs:17:10

View file

@ -2,7 +2,7 @@ error[E0574]: expected struct, variant or union type, found type parameter `T`
--> $DIR/lexical-scopes.rs:3:13 --> $DIR/lexical-scopes.rs:3:13
| |
LL | fn f<T>() { LL | fn f<T>() {
| - found this type pararmeter | - found this type parameter
LL | let t = T { i: 0 }; LL | let t = T { i: 0 };
| ^ not a struct, variant or union type | ^ not a struct, variant or union type

View file

@ -2,7 +2,7 @@ error[E0574]: expected struct, variant or union type, found type parameter `Baz`
--> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13 --> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13
| |
LL | impl<Baz> Foo<Baz> for Bar { LL | impl<Baz> Foo<Baz> for Bar {
| --- found this type pararmeter | --- found this type parameter
... ...
LL | Baz { num } => num, LL | Baz { num } => num,
| ^^^ not a struct, variant or union type | ^^^ not a struct, variant or union type

View file

@ -4,7 +4,7 @@ error[E0404]: expected trait, found type parameter `Add`
LL | impl<T: Clone, Add> Add for Foo<T> { LL | impl<T: Clone, Add> Add for Foo<T> {
| --- ^^^ not a trait | --- ^^^ not a trait
| | | |
| found this type pararmeter | found this type parameter
| |
help: consider importing this trait instead help: consider importing this trait instead
| |

View file

@ -11,9 +11,15 @@ mod tests;
pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
"aarch64-apple-darwin", "aarch64-apple-darwin",
"aarch64-fuchsia", "aarch64-fuchsia",
"aarch64-linux-android",
"aarch64-unknown-linux-gnu", "aarch64-unknown-linux-gnu",
"arm-linux-androideabi",
"armv7-linux-androideabi",
"i686-linux-android",
"i686-unknown-linux-gnu",
"x86_64-apple-darwin", "x86_64-apple-darwin",
"x86_64-fuchsia", "x86_64-fuchsia",
"x86_64-linux-android",
"x86_64-unknown-freebsd", "x86_64-unknown-freebsd",
"x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnu",
]; ];