Auto merge of #121055 - matthiaskrgr:rollup-bzn5sda, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #118882 (Check normalized call signature for WF in mir typeck)
 - #120999 (rustdoc: replace `clean::InstantiationParam` with `clean::GenericArg`)
 - #121002 (remove unnecessary calls to `commit_if_ok`)
 - #121005 (Remove jsha from the rustdoc review rotation)
 - #121014 (Remove `force_print_diagnostic`)
 - #121043 (add lcnr to the compiler-team assignment group)
 - #121046 (Fix incorrect use of `compile_fail`)
 - #121047 (Do not assemble candidates for default impls)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-14 03:21:31 +00:00
commit 7508c3e4c1
23 changed files with 326 additions and 234 deletions

View File

@ -1432,7 +1432,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return; return;
} }
}; };
let (sig, map) = tcx.instantiate_bound_regions(sig, |br| { let (unnormalized_sig, map) = tcx.instantiate_bound_regions(sig, |br| {
use crate::renumber::RegionCtxt; use crate::renumber::RegionCtxt;
let region_ctxt_fn = || { let region_ctxt_fn = || {
@ -1454,7 +1454,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
region_ctxt_fn, region_ctxt_fn,
) )
}); });
debug!(?sig); debug!(?unnormalized_sig);
// IMPORTANT: We have to prove well formed for the function signature before // IMPORTANT: We have to prove well formed for the function signature before
// we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc` // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
// get normalized away, causing us to ignore the `'b: 'a` bound used by the function. // get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
@ -1464,7 +1464,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// //
// See #91068 for an example. // See #91068 for an example.
self.prove_predicates( self.prove_predicates(
sig.inputs_and_output.iter().map(|ty| { unnormalized_sig.inputs_and_output.iter().map(|ty| {
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
ty.into(), ty.into(),
))) )))
@ -1472,7 +1472,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
term_location.to_locations(), term_location.to_locations(),
ConstraintCategory::Boring, ConstraintCategory::Boring,
); );
let sig = self.normalize(sig, term_location);
let sig = self.normalize(unnormalized_sig, term_location);
// HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))`
// with built-in `Fn` implementations, since the impl may not be
// well-formed itself.
if sig != unnormalized_sig {
self.prove_predicates(
sig.inputs_and_output.iter().map(|ty| {
ty::Binder::dummy(ty::PredicateKind::Clause(
ty::ClauseKind::WellFormed(ty.into()),
))
}),
term_location.to_locations(),
ConstraintCategory::Boring,
);
}
self.check_call_dest(body, term, &sig, *destination, *target, term_location); self.check_call_dest(body, term, &sig, *destination, *target, term_location);
// The ordinary liveness rules will ensure that all // The ordinary liveness rules will ensure that all

View File

@ -78,6 +78,7 @@ use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::io::Write; use std::io::Write;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::ops::DerefMut;
use std::panic; use std::panic;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -666,22 +667,51 @@ impl DiagCtxt {
/// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
/// the overall count of emitted error diagnostics. /// the overall count of emitted error diagnostics.
pub fn reset_err_count(&self) { pub fn reset_err_count(&self) {
// Use destructuring so that if a field gets added to `DiagCtxtInner`, it's impossible to
// fail to update this method as well.
let mut inner = self.inner.borrow_mut(); let mut inner = self.inner.borrow_mut();
inner.stashed_err_count = 0; let DiagCtxtInner {
inner.deduplicated_err_count = 0; flags: _,
inner.deduplicated_warn_count = 0; err_guars,
inner.must_produce_diag = false; lint_err_guars,
inner.has_printed = false; delayed_bugs,
inner.suppressed_expected_diag = false; stashed_err_count,
deduplicated_err_count,
deduplicated_warn_count,
emitter: _,
must_produce_diag,
has_printed,
suppressed_expected_diag,
taught_diagnostics,
emitted_diagnostic_codes,
emitted_diagnostics,
stashed_diagnostics,
future_breakage_diagnostics,
check_unstable_expect_diagnostics,
unstable_expect_diagnostics,
fulfilled_expectations,
ice_file: _,
} = inner.deref_mut();
// actually free the underlying memory (which `clear` would not do) // For the `Vec`s and `HashMap`s, we overwrite with an empty container to free the
inner.err_guars = Default::default(); // underlying memory (which `clear` would not do).
inner.lint_err_guars = Default::default(); *err_guars = Default::default();
inner.delayed_bugs = Default::default(); *lint_err_guars = Default::default();
inner.taught_diagnostics = Default::default(); *delayed_bugs = Default::default();
inner.emitted_diagnostic_codes = Default::default(); *stashed_err_count = 0;
inner.emitted_diagnostics = Default::default(); *deduplicated_err_count = 0;
inner.stashed_diagnostics = Default::default(); *deduplicated_warn_count = 0;
*must_produce_diag = false;
*has_printed = false;
*suppressed_expected_diag = false;
*taught_diagnostics = Default::default();
*emitted_diagnostic_codes = Default::default();
*emitted_diagnostics = Default::default();
*stashed_diagnostics = Default::default();
*future_breakage_diagnostics = Default::default();
*check_unstable_expect_diagnostics = false;
*unstable_expect_diagnostics = Default::default();
*fulfilled_expectations = Default::default();
} }
/// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key. /// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key.
@ -780,11 +810,12 @@ impl DiagCtxt {
match (errors.len(), warnings.len()) { match (errors.len(), warnings.len()) {
(0, 0) => return, (0, 0) => return,
(0, _) => { (0, _) => {
// Use `inner.emitter` directly, otherwise the warning might not be emitted, e.g. // Use `ForceWarning` rather than `Warning` to guarantee emission, e.g. with a
// with a configuration like `--cap-lints allow --force-warn bare_trait_objects`. // configuration like `--cap-lints allow --force-warn bare_trait_objects`.
inner inner.emit_diagnostic(Diagnostic::new(
.emitter ForceWarning(None),
.emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))); DiagnosticMessage::Str(warnings),
));
} }
(_, 0) => { (_, 0) => {
inner.emit_diagnostic(Diagnostic::new(Error, errors)); inner.emit_diagnostic(Diagnostic::new(Error, errors));
@ -812,20 +843,23 @@ impl DiagCtxt {
error_codes.sort(); error_codes.sort();
if error_codes.len() > 1 { if error_codes.len() > 1 {
let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
inner.failure_note(format!( let msg1 = format!(
"Some errors have detailed explanations: {}{}", "Some errors have detailed explanations: {}{}",
error_codes[..limit].join(", "), error_codes[..limit].join(", "),
if error_codes.len() > 9 { "..." } else { "." } if error_codes.len() > 9 { "..." } else { "." }
)); );
inner.failure_note(format!( let msg2 = format!(
"For more information about an error, try `rustc --explain {}`.", "For more information about an error, try `rustc --explain {}`.",
&error_codes[0] &error_codes[0]
)); );
inner.emit_diagnostic(Diagnostic::new(FailureNote, msg1));
inner.emit_diagnostic(Diagnostic::new(FailureNote, msg2));
} else { } else {
inner.failure_note(format!( let msg = format!(
"For more information about this error, try `rustc --explain {}`.", "For more information about this error, try `rustc --explain {}`.",
&error_codes[0] &error_codes[0]
)); );
inner.emit_diagnostic(Diagnostic::new(FailureNote, msg));
} }
} }
} }
@ -848,10 +882,6 @@ impl DiagCtxt {
self.inner.borrow_mut().taught_diagnostics.insert(code) self.inner.borrow_mut().taught_diagnostics.insert(code)
} }
pub fn force_print_diagnostic(&self, db: Diagnostic) {
self.inner.borrow_mut().emitter.emit_diagnostic(db);
}
pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option<ErrorGuaranteed> { pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_diagnostic(diagnostic) self.inner.borrow_mut().emit_diagnostic(diagnostic)
} }
@ -1179,7 +1209,7 @@ impl DiagCtxt {
span: impl Into<MultiSpan>, span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>, msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> { ) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Note, msg).with_span(span) self.struct_note(msg).with_span(span)
} }
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
@ -1207,6 +1237,15 @@ impl DiagCtxt {
DiagnosticBuilder::new(self, Help, msg) DiagnosticBuilder::new(self, Help, msg)
} }
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_failure_note(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, FailureNote, msg)
}
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
#[track_caller] #[track_caller]
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
@ -1406,10 +1445,6 @@ impl DiagCtxtInner {
.or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied()) .or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
} }
fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
self.emit_diagnostic(Diagnostic::new(FailureNote, msg));
}
fn flush_delayed(&mut self) { fn flush_delayed(&mut self) {
if self.delayed_bugs.is_empty() { if self.delayed_bugs.is_empty() {
return; return;

View File

@ -285,13 +285,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields
fields .sub(a_is_expected)
.sub(a_is_expected) .relate(a, b)
.relate(a, b) .map(move |_| InferOk { value: (), obligations: fields.obligations })
.map(move |_| InferOk { value: (), obligations: fields.obligations })
})
} }
/// Makes `a == b`; the expectation is set by the call to /// Makes `a == b`; the expectation is set by the call to
@ -302,13 +300,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields
fields .equate(a_is_expected)
.equate(a_is_expected) .relate(a, b)
.relate(a, b) .map(move |_| InferOk { value: (), obligations: fields.obligations })
.map(move |_| InferOk { value: (), obligations: fields.obligations })
})
} }
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
@ -317,13 +313,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields
fields .lub(a_is_expected)
.lub(a_is_expected) .relate(a, b)
.relate(a, b) .map(move |t| InferOk { value: t, obligations: fields.obligations })
.map(move |t| InferOk { value: t, obligations: fields.obligations })
})
} }
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
@ -332,13 +326,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
T: Relate<'tcx>, T: Relate<'tcx>,
{ {
let Trace { at, trace, a_is_expected } = self; let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); fields
fields .glb(a_is_expected)
.glb(a_is_expected) .relate(a, b)
.relate(a, b) .map(move |t| InferOk { value: t, obligations: fields.obligations })
.map(move |t| InferOk { value: t, obligations: fields.obligations })
})
} }
} }

View File

@ -620,42 +620,40 @@ impl<'tcx> InferCtxt<'tcx> {
variables1: &OriginalQueryValues<'tcx>, variables1: &OriginalQueryValues<'tcx>,
variables2: impl Fn(BoundVar) -> GenericArg<'tcx>, variables2: impl Fn(BoundVar) -> GenericArg<'tcx>,
) -> InferResult<'tcx, ()> { ) -> InferResult<'tcx, ()> {
self.commit_if_ok(|_| { let mut obligations = vec![];
let mut obligations = vec![]; for (index, value1) in variables1.var_values.iter().enumerate() {
for (index, value1) in variables1.var_values.iter().enumerate() { let value2 = variables2(BoundVar::new(index));
let value2 = variables2(BoundVar::new(index));
match (value1.unpack(), value2.unpack()) { match (value1.unpack(), value2.unpack()) {
(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
obligations.extend( obligations.extend(
self.at(cause, param_env) self.at(cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)? .eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(), .into_obligations(),
); );
} }
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2)) (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
if re1.is_erased() && re2.is_erased() => if re1.is_erased() && re2.is_erased() =>
{ {
// no action needed // no action needed
} }
(GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
obligations.extend( obligations.extend(
self.at(cause, param_env) self.at(cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)? .eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(), .into_obligations(),
); );
} }
(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?; let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?;
obligations.extend(ok.into_obligations()); obligations.extend(ok.into_obligations());
} }
_ => { _ => {
bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
}
} }
} }
Ok(InferOk { value: (), obligations }) }
}) Ok(InferOk { value: (), obligations })
} }
} }

View File

@ -4,7 +4,7 @@ use crate::query::plumbing::CycleError;
use crate::query::DepKind; use crate::query::DepKind;
use crate::query::{QueryContext, QueryStackFrame}; use crate::query::{QueryContext, QueryStackFrame};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{DiagCtxt, Diagnostic, DiagnosticBuilder, Level}; use rustc_errors::{DiagCtxt, DiagnosticBuilder};
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::Span; use rustc_span::Span;
@ -628,15 +628,15 @@ pub fn print_query_stack<Qcx: QueryContext>(
}; };
if Some(count_printed) < num_frames || num_frames.is_none() { if Some(count_printed) < num_frames || num_frames.is_none() {
// Only print to stderr as many stack frames as `num_frames` when present. // Only print to stderr as many stack frames as `num_frames` when present.
let mut diag = Diagnostic::new( // FIXME: needs translation
Level::FailureNote, #[allow(rustc::diagnostic_outside_of_impl)]
format!( #[allow(rustc::untranslatable_diagnostic)]
"#{} [{:?}] {}", dcx.struct_failure_note(format!(
count_printed, query_info.query.dep_kind, query_info.query.description "#{} [{:?}] {}",
), count_printed, query_info.query.dep_kind, query_info.query.description
); ))
diag.span = query_info.job.span.into(); .with_span(query_info.job.span)
dcx.force_print_diagnostic(diag); .emit();
count_printed += 1; count_printed += 1;
} }

View File

@ -337,6 +337,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let mut consider_impls_for_simplified_type = |simp| { let mut consider_impls_for_simplified_type = |simp| {
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
for &impl_def_id in impls_for_type { for &impl_def_id in impls_for_type {
// For every `default impl`, there's always a non-default `impl`
// that will *also* apply. There's no reason to register a candidate
// for this impl, since it is *not* proof that the trait goal holds.
if tcx.defaultness(impl_def_id).is_default() {
return;
}
match G::consider_impl_candidate(self, goal, impl_def_id) { match G::consider_impl_candidate(self, goal, impl_def_id) {
Ok(candidate) => candidates.push(candidate), Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (), Err(NoSolution) => (),
@ -440,6 +447,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
for &impl_def_id in trait_impls.blanket_impls() { for &impl_def_id in trait_impls.blanket_impls() {
// For every `default impl`, there's always a non-default `impl`
// that will *also* apply. There's no reason to register a candidate
// for this impl, since it is *not* proof that the trait goal holds.
if tcx.defaultness(impl_def_id).is_default() {
return;
}
match G::consider_impl_candidate(self, goal, impl_def_id) { match G::consider_impl_candidate(self, goal, impl_def_id) {
Ok(candidate) => candidates.push(candidate), Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (), Err(NoSolution) => (),

View File

@ -566,6 +566,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
{ {
return; return;
} }
// For every `default impl`, there's always a non-default `impl`
// that will *also* apply. There's no reason to register a candidate
// for this impl, since it is *not* proof that the trait goal holds.
if self.tcx().defaultness(impl_def_id).is_default() {
return;
}
if self.reject_fn_ptr_impls( if self.reject_fn_ptr_impls(
impl_def_id, impl_def_id,
obligation, obligation,

View File

@ -192,13 +192,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut obligations, &mut obligations,
); );
obligations.extend(self.infcx.commit_if_ok(|_| { obligations.extend(
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate) .sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
.map(|InferOk { obligations, .. }| obligations) .map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented) .map_err(|_| Unimplemented)?,
})?); );
// FIXME(compiler-errors): I don't think this is needed. // FIXME(compiler-errors): I don't think this is needed.
if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() { if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() {
@ -532,13 +532,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut nested, &mut nested,
); );
nested.extend(self.infcx.commit_if_ok(|_| { nested.extend(
self.infcx self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref) .sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
.map(|InferOk { obligations, .. }| obligations) .map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented) .map_err(|_| Unimplemented)?,
})?); );
// Check supertraits hold. This is so that their associated type bounds // Check supertraits hold. This is so that their associated type bounds
// will be checked in the code below. // will be checked in the code below.

View File

@ -171,7 +171,7 @@ pub struct Child {
/// The handle for writing to the child's standard input (stdin), if it /// The handle for writing to the child's standard input (stdin), if it
/// has been captured. You might find it helpful to do /// has been captured. You might find it helpful to do
/// ///
/// ```compile_fail,E0425 /// ```ignore (incomplete)
/// let stdin = child.stdin.take().unwrap(); /// let stdin = child.stdin.take().unwrap();
/// ``` /// ```
/// ///
@ -183,7 +183,7 @@ pub struct Child {
/// The handle for reading from the child's standard output (stdout), if it /// The handle for reading from the child's standard output (stdout), if it
/// has been captured. You might find it helpful to do /// has been captured. You might find it helpful to do
/// ///
/// ```compile_fail,E0425 /// ```ignore (incomplete)
/// let stdout = child.stdout.take().unwrap(); /// let stdout = child.stdout.take().unwrap();
/// ``` /// ```
/// ///
@ -195,7 +195,7 @@ pub struct Child {
/// The handle for reading from the child's standard error (stderr), if it /// The handle for reading from the child's standard error (stderr), if it
/// has been captured. You might find it helpful to do /// has been captured. You might find it helpful to do
/// ///
/// ```compile_fail,E0425 /// ```ignore (incomplete)
/// let stderr = child.stderr.take().unwrap(); /// let stderr = child.stderr.take().unwrap();
/// ``` /// ```
/// ///

View File

@ -254,16 +254,14 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
} }
fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime { fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
let def = cx.tcx.named_bound_var(lifetime.hir_id);
if let Some( if let Some(
rbv::ResolvedArg::EarlyBound(node_id) rbv::ResolvedArg::EarlyBound(did)
| rbv::ResolvedArg::LateBound(_, _, node_id) | rbv::ResolvedArg::LateBound(_, _, did)
| rbv::ResolvedArg::Free(_, node_id), | rbv::ResolvedArg::Free(_, did),
) = def ) = cx.tcx.named_bound_var(lifetime.hir_id)
&& let Some(lt) = cx.args.get(&did).and_then(|arg| arg.as_lt())
{ {
if let Some(lt) = cx.args.get(&node_id).and_then(|p| p.as_lt()).cloned() { return lt.clone();
return lt;
}
} }
Lifetime(lifetime.ident.name) Lifetime(lifetime.ident.name)
} }
@ -1791,12 +1789,12 @@ fn maybe_expand_private_type_alias<'tcx>(
_ => None, _ => None,
}); });
if let Some(lt) = lifetime { if let Some(lt) = lifetime {
let cleaned = if !lt.is_anonymous() { let lt = if !lt.is_anonymous() {
clean_lifetime(lt, cx) clean_lifetime(lt, cx)
} else { } else {
Lifetime::elided() Lifetime::elided()
}; };
args.insert(param.def_id.to_def_id(), InstantiationParam::Lifetime(cleaned)); args.insert(param.def_id.to_def_id(), GenericArg::Lifetime(lt));
} }
indices.lifetimes += 1; indices.lifetimes += 1;
} }
@ -1805,44 +1803,20 @@ fn maybe_expand_private_type_alias<'tcx>(
let type_ = generic_args.args.iter().find_map(|arg| match arg { let type_ = generic_args.args.iter().find_map(|arg| match arg {
hir::GenericArg::Type(ty) => { hir::GenericArg::Type(ty) => {
if indices.types == j { if indices.types == j {
return Some(ty); return Some(*ty);
} }
j += 1; j += 1;
None None
} }
_ => None, _ => None,
}); });
if let Some(ty) = type_ { if let Some(ty) = type_.or(*default) {
args.insert( args.insert(param.def_id.to_def_id(), GenericArg::Type(clean_ty(ty, cx)));
param.def_id.to_def_id(),
InstantiationParam::Type(clean_ty(ty, cx)),
);
} else if let Some(default) = *default {
args.insert(
param.def_id.to_def_id(),
InstantiationParam::Type(clean_ty(default, cx)),
);
} }
indices.types += 1; indices.types += 1;
} }
hir::GenericParamKind::Const { .. } => { // FIXME(#82852): Instantiate const parameters.
let mut j = 0; hir::GenericParamKind::Const { .. } => {}
let const_ = generic_args.args.iter().find_map(|arg| match arg {
hir::GenericArg::Const(ct) => {
if indices.consts == j {
return Some(ct);
}
j += 1;
None
}
_ => None,
});
if let Some(_) = const_ {
args.insert(param.def_id.to_def_id(), InstantiationParam::Constant);
}
// FIXME(const_generics_defaults)
indices.consts += 1;
}
} }
} }

View File

@ -2228,6 +2228,16 @@ pub(crate) enum GenericArg {
Infer, Infer,
} }
impl GenericArg {
pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
if let Self::Lifetime(lt) = self { Some(lt) } else { None }
}
pub(crate) fn as_ty(&self) -> Option<&Type> {
if let Self::Type(ty) = self { Some(ty) } else { None }
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) enum GenericArgs { pub(crate) enum GenericArgs {
AngleBracketed { args: Box<[GenericArg]>, bindings: ThinVec<TypeBinding> }, AngleBracketed { args: Box<[GenericArg]>, bindings: ThinVec<TypeBinding> },
@ -2530,35 +2540,6 @@ pub(crate) enum TypeBindingKind {
Constraint { bounds: Vec<GenericBound> }, Constraint { bounds: Vec<GenericBound> },
} }
/// The type, lifetime, or constant that a private type alias's parameter should be
/// replaced with when expanding a use of that type alias.
///
/// For example:
///
/// ```
/// type PrivAlias<T> = Vec<T>;
///
/// pub fn public_fn() -> PrivAlias<i32> { vec![] }
/// ```
///
/// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
/// [`InstantiationParam`] is used to record that `T` should be mapped to `i32`.
pub(crate) enum InstantiationParam {
Type(Type),
Lifetime(Lifetime),
Constant,
}
impl InstantiationParam {
pub(crate) fn as_ty(&self) -> Option<&Type> {
if let Self::Type(ty) = self { Some(ty) } else { None }
}
pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
if let Self::Lifetime(lt) = self { Some(lt) } else { None }
}
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger. // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts { mod size_asserts {

View File

@ -44,10 +44,13 @@ pub(crate) struct DocContext<'tcx> {
/// Used while populating `external_traits` to ensure we don't process the same trait twice at /// Used while populating `external_traits` to ensure we don't process the same trait twice at
/// the same time. /// the same time.
pub(crate) active_extern_traits: DefIdSet, pub(crate) active_extern_traits: DefIdSet,
// The current set of parameter instantiations, /// The current set of parameter instantiations for expanding type aliases at the HIR level.
// for expanding type aliases at the HIR level: ///
/// Table `DefId` of type, lifetime, or const parameter -> instantiated type, lifetime, or const /// Maps from the `DefId` of a lifetime or type parameter to the
pub(crate) args: DefIdMap<clean::InstantiationParam>, /// generic argument it's currently instantiated to in this context.
// FIXME(#82852): We don't record const params since we don't visit const exprs at all and
// therefore wouldn't use the corresp. generic arg anyway. Add support for them.
pub(crate) args: DefIdMap<clean::GenericArg>,
pub(crate) current_type_aliases: DefIdMap<usize>, pub(crate) current_type_aliases: DefIdMap<usize>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
pub(crate) impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>, pub(crate) impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
@ -87,7 +90,7 @@ impl<'tcx> DocContext<'tcx> {
/// the generic parameters for a type alias' RHS. /// the generic parameters for a type alias' RHS.
pub(crate) fn enter_alias<F, R>( pub(crate) fn enter_alias<F, R>(
&mut self, &mut self,
args: DefIdMap<clean::InstantiationParam>, args: DefIdMap<clean::GenericArg>,
def_id: DefId, def_id: DefId,
f: F, f: F,
) -> R ) -> R

View File

@ -9,8 +9,8 @@ LL | |
LL | | }); LL | | });
| |______^ expected due to this | |______^ expected due to this
| |
= note: expected closure signature `fn(_, _) -> _` = note: expected closure signature `fn(_, u32) -> _`
found closure signature `fn(u32, i32) -> _` found closure signature `fn(_, i32) -> _`
note: required by a bound in `with_closure` note: required by a bound in `with_closure`
--> $DIR/expect-infer-var-appearing-twice.rs:2:14 --> $DIR/expect-infer-var-appearing-twice.rs:2:14
| |

View File

@ -0,0 +1,27 @@
// <https://github.com/rust-lang/rust/issues/114936>
fn whoops(
s: String,
f: impl for<'s> FnOnce(&'s str) -> (&'static str, [&'static &'s (); 0]),
) -> &'static str
{
f(&s).0
//~^ ERROR `s` does not live long enough
}
// <https://github.com/rust-lang/rust/issues/118876>
fn extend<T>(input: &T) -> &'static T {
struct Bounded<'a, 'b: 'static, T>(&'a T, [&'b (); 0]);
let n: Box<dyn FnOnce(&T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
n(input).0
//~^ ERROR borrowed data escapes outside of function
}
// <https://github.com/rust-lang/rust/issues/118876>
fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
struct Bounded<'a, 'b: 'static, T>(&'a mut T, [&'b (); 0]);
let mut n: Box<dyn FnMut(&mut T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
n(input).0
//~^ ERROR borrowed data escapes outside of function
}
fn main() {}

View File

@ -0,0 +1,47 @@
error[E0597]: `s` does not live long enough
--> $DIR/check-normalized-sig-for-wf.rs:7:7
|
LL | s: String,
| - binding `s` declared here
...
LL | f(&s).0
| --^^-
| | |
| | borrowed value does not live long enough
| argument requires that `s` is borrowed for `'static`
LL |
LL | }
| - `s` dropped here while still borrowed
error[E0521]: borrowed data escapes outside of function
--> $DIR/check-normalized-sig-for-wf.rs:15:5
|
LL | fn extend<T>(input: &T) -> &'static T {
| ----- - let's call the lifetime of this reference `'1`
| |
| `input` is a reference that is only valid in the function body
...
LL | n(input).0
| ^^^^^^^^
| |
| `input` escapes the function body here
| argument requires that `'1` must outlive `'static`
error[E0521]: borrowed data escapes outside of function
--> $DIR/check-normalized-sig-for-wf.rs:23:5
|
LL | fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
| -- ----- `input` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
...
LL | n(input).0
| ^^^^^^^^
| |
| `input` escapes the function body here
| argument requires that `'a` must outlive `'static`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0521, E0597.
For more information about an error, try `rustc --explain E0521`.

View File

@ -20,5 +20,5 @@ default impl<T> Foo for T {
fn main() { fn main() {
println!("{}", MyStruct.foo_one()); println!("{}", MyStruct.foo_one());
//~^ ERROR the method //~^ ERROR no method named `foo_one` found for struct `MyStruct` in the current scope
} }

View File

@ -8,27 +8,15 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete = help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default = note: `#[warn(incomplete_features)]` on by default
error[E0599]: the method `foo_one` exists for struct `MyStruct`, but its trait bounds were not satisfied error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope
--> $DIR/specialization-trait-not-implemented.rs:22:29 --> $DIR/specialization-trait-not-implemented.rs:22:29
| |
LL | struct MyStruct; LL | struct MyStruct;
| --------------- method `foo_one` not found for this struct because it doesn't satisfy `MyStruct: Foo` | --------------- method `foo_one` not found for this struct
... ...
LL | println!("{}", MyStruct.foo_one()); LL | println!("{}", MyStruct.foo_one());
| ^^^^^^^ method cannot be called on `MyStruct` due to unsatisfied trait bounds | ^^^^^^^ method not found in `MyStruct`
| |
note: trait bound `MyStruct: Foo` was not satisfied
--> $DIR/specialization-trait-not-implemented.rs:14:1
|
LL | default impl<T> Foo for T {
| ^^^^^^^^^^^^^^^^---^^^^^-
| |
| unsatisfied trait bound introduced here
note: the trait `Foo` must be implemented
--> $DIR/specialization-trait-not-implemented.rs:7:1
|
LL | trait Foo {
| ^^^^^^^^^
= help: items from traits can only be used if the trait is implemented and in scope = help: items from traits can only be used if the trait is implemented and in scope
note: `Foo` defines an item `foo_one`, perhaps you need to implement it note: `Foo` defines an item `foo_one`, perhaps you need to implement it
--> $DIR/specialization-trait-not-implemented.rs:7:1 --> $DIR/specialization-trait-not-implemented.rs:7:1

View File

@ -7,6 +7,7 @@ struct Z;
default impl S {} //~ ERROR inherent impls cannot be `default` default impl S {} //~ ERROR inherent impls cannot be `default`
default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default
//~^ ERROR `S` cannot be sent between threads safely
default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default
//~^ ERROR negative impls cannot be default impls //~^ ERROR negative impls cannot be default impls

View File

@ -26,8 +26,19 @@ LL | default unsafe impl Send for S {}
| | | |
| default because of this | default because of this
error[E0277]: `S` cannot be sent between threads safely
--> $DIR/validation.rs:9:1
|
LL | default unsafe impl Send for S {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `S` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `S`
= help: the trait `Send` is implemented for `S`
= help: see issue #48214
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
error: impls of auto traits cannot be default error: impls of auto traits cannot be default
--> $DIR/validation.rs:10:15 --> $DIR/validation.rs:11:15
| |
LL | default impl !Send for Z {} LL | default impl !Send for Z {}
| ------- ^^^^ auto trait | ------- ^^^^ auto trait
@ -35,17 +46,18 @@ LL | default impl !Send for Z {}
| default because of this | default because of this
error[E0750]: negative impls cannot be default impls error[E0750]: negative impls cannot be default impls
--> $DIR/validation.rs:10:1 --> $DIR/validation.rs:11:1
| |
LL | default impl !Send for Z {} LL | default impl !Send for Z {}
| ^^^^^^^ ^ | ^^^^^^^ ^
error[E0750]: negative impls cannot be default impls error[E0750]: negative impls cannot be default impls
--> $DIR/validation.rs:14:1 --> $DIR/validation.rs:15:1
| |
LL | default impl !Tr for S {} LL | default impl !Tr for S {}
| ^^^^^^^ ^ | ^^^^^^^ ^
error: aborting due to 5 previous errors; 1 warning emitted error: aborting due to 6 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0750`. Some errors have detailed explanations: E0277, E0750.
For more information about an error, try `rustc --explain E0277`.

View File

@ -1,14 +1,12 @@
error[E0275]: overflow evaluating the requirement `T: Trait<_>` error[E0119]: conflicting implementations of trait `Trait<_>`
| --> $DIR/issue-45814.rs:10:1
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`)
note: required for `T` to implement `Trait<_>`
--> $DIR/issue-45814.rs:9:20
| |
LL | default impl<T, U> Trait<T> for U {} LL | default impl<T, U> Trait<T> for U {}
| ^^^^^^^^ ^ | --------------------------------- first implementation here
= note: 128 redundant requirements hidden LL |
= note: required for `T` to implement `Trait<_>` LL | impl<T> Trait<<T as Iterator>::Item> for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0275`. For more information about this error, try `rustc --explain E0119`.

View File

@ -1,14 +1,12 @@
error[E0275]: overflow evaluating the requirement `T: Trait<_>` error[E0119]: conflicting implementations of trait `Trait<_>`
| --> $DIR/issue-45814.rs:10:1
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`)
note: required for `T` to implement `Trait<_>`
--> $DIR/issue-45814.rs:9:20
| |
LL | default impl<T, U> Trait<T> for U {} LL | default impl<T, U> Trait<T> for U {}
| ^^^^^^^^ ^ | --------------------------------- first implementation here
= note: 128 redundant requirements hidden LL |
= note: required for `T` to implement `Trait<_>` LL | impl<T> Trait<<T as Iterator>::Item> for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0275`. For more information about this error, try `rustc --explain E0119`.

View File

@ -1,4 +1,3 @@
//~ ERROR overflow evaluating the requirement `T: Trait<_>`
// revisions: current negative // revisions: current negative
#![feature(specialization)] #![feature(specialization)]
#![cfg_attr(negative, feature(with_negative_coherence))] #![cfg_attr(negative, feature(with_negative_coherence))]
@ -9,5 +8,6 @@ pub trait Trait<T> {}
default impl<T, U> Trait<T> for U {} default impl<T, U> Trait<T> for U {}
impl<T> Trait<<T as Iterator>::Item> for T {} impl<T> Trait<<T as Iterator>::Item> for T {}
//~^ ERROR conflicting implementations of trait `Trait<_>`
fn main() {} fn main() {}

View File

@ -651,6 +651,7 @@ compiler-team = [
"@petrochenkov", "@petrochenkov",
"@davidtwco", "@davidtwco",
"@estebank", "@estebank",
"@lcnr",
"@oli-obk", "@oli-obk",
"@pnkfelix", "@pnkfelix",
"@wesleywiser", "@wesleywiser",
@ -680,7 +681,6 @@ infra-ci = [
"@Kobzol", "@Kobzol",
] ]
rustdoc = [ rustdoc = [
"@jsha",
"@GuillaumeGomez", "@GuillaumeGomez",
"@notriddle", "@notriddle",
"@fmease", "@fmease",