1
Fork 0

Auto merge of #3630 - rust-lang:rustup-2024-05-25, r=saethlin

Automatic Rustup
This commit is contained in:
bors 2024-05-25 12:46:16 +00:00
commit 331bb3f10d
72 changed files with 811 additions and 586 deletions

View file

@ -4252,6 +4252,7 @@ dependencies = [
"rustc_fluent_macro", "rustc_fluent_macro",
"rustc_hir", "rustc_hir",
"rustc_index", "rustc_index",
"rustc_infer",
"rustc_macros", "rustc_macros",
"rustc_middle", "rustc_middle",
"rustc_mir_build", "rustc_mir_build",

View file

@ -29,8 +29,8 @@ use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, Debugger
use rustc_middle::middle::exported_symbols; use rustc_middle::middle::exported_symbols;
use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_middle::middle::lang_items; use rustc_middle::middle::lang_items;
use rustc_middle::mir::BinOp;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
use rustc_middle::mir::BinOp;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt};

View file

@ -139,10 +139,9 @@ where
ErrorHandled::TooGeneric(span) ErrorHandled::TooGeneric(span)
} }
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span), err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span),
err_inval!(Layout(LayoutError::ReferencesError(guar))) => ErrorHandled::Reported( err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
ReportedErrorInfo::tainted_by_errors(guar), ErrorHandled::Reported(ReportedErrorInfo::tainted_by_errors(guar), span)
span, }
),
// Report remaining errors. // Report remaining errors.
_ => { _ => {
let (our_span, frames) = get_span_and_frames(); let (our_span, frames) = get_span_and_frames();

View file

@ -14,10 +14,10 @@
#![feature(yeet_expr)] #![feature(yeet_expr)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
pub mod check_consts;
pub mod const_eval; pub mod const_eval;
mod errors; mod errors;
pub mod interpret; pub mod interpret;
pub mod transform;
pub mod util; pub mod util;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;

View file

@ -1,2 +0,0 @@
pub mod check_consts;
pub mod validate;

View file

@ -164,9 +164,8 @@ pub fn check_intrinsic_type(
) { ) {
let generics = tcx.generics_of(intrinsic_id); let generics = tcx.generics_of(intrinsic_id);
let param = |n| { let param = |n| {
if let Some(&ty::GenericParamDef { if let &ty::GenericParamDef { name, kind: ty::GenericParamDefKind::Type { .. }, .. } =
name, kind: ty::GenericParamDefKind::Type { .. }, .. generics.param_at(n as usize, tcx)
}) = generics.opt_param_at(n as usize, tcx)
{ {
Ty::new_param(tcx, n, name) Ty::new_param(tcx, n, name)
} else { } else {

View file

@ -461,83 +461,55 @@ pub(super) fn explicit_predicates_of<'tcx>(
} }
} }
} else { } else {
if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs { if matches!(def_kind, DefKind::AnonConst)
let hir_id = tcx.local_def_id_to_hir_id(def_id); && tcx.features().generic_const_exprs
let parent_def_id = tcx.hir().get_parent_item(hir_id); && let Some(defaulted_param_def_id) =
tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id))
{
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
//
// struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
// ^^^ explicit_predicates_of on
// parent item we dont have set as the
// parent of generics returned by `generics_of`
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
// and we would be calling `explicit_predicates_of(Foo)` here
let parent_def_id = tcx.local_parent(def_id);
let parent_preds = tcx.explicit_predicates_of(parent_def_id);
if let Some(defaulted_param_def_id) = // If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter
tcx.hir().opt_const_param_default_param_def_id(hir_id) // will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution
{ // to #106994 is implemented.
// In `generics_of` we set the generics' parent to be our parent's parent which means that let filtered_predicates = parent_preds
// we lose out on the predicates of our actual parent if we dont return those predicates here. .predicates
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary) .into_iter()
// .filter(|(pred, _)| {
// struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait; if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() {
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling match ct.kind() {
// ^^^ explicit_predicates_of on ty::ConstKind::Param(param_const) => {
// parent item we dont have set as the let defaulted_param_idx = tcx
// parent of generics returned by `generics_of` .generics_of(parent_def_id)
// .param_def_id_to_index[&defaulted_param_def_id.to_def_id()];
// In the above code we want the anon const to have predicates in its param env for `T: Trait` param_const.index < defaulted_param_idx
// and we would be calling `explicit_predicates_of(Foo)` here
let parent_preds = tcx.explicit_predicates_of(parent_def_id);
// If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter
// will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution
// to #106994 is implemented.
let filtered_predicates = parent_preds
.predicates
.into_iter()
.filter(|(pred, _)| {
if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() {
match ct.kind() {
ty::ConstKind::Param(param_const) => {
let defaulted_param_idx = tcx
.generics_of(parent_def_id)
.param_def_id_to_index[&defaulted_param_def_id.to_def_id()];
param_const.index < defaulted_param_idx
}
_ => bug!(
"`ConstArgHasType` in `predicates_of`\
that isn't a `Param` const"
),
} }
} else { _ => bug!(
true "`ConstArgHasType` in `predicates_of`\
that isn't a `Param` const"
),
} }
}) } else {
.cloned(); true
return GenericPredicates { }
parent: parent_preds.parent, })
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, .cloned();
}; return GenericPredicates {
} parent: parent_preds.parent,
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
let parent_def_kind = tcx.def_kind(parent_def_id); };
if matches!(parent_def_kind, DefKind::OpaqueTy) {
// In `instantiate_identity` we inherit the predicates of our parent.
// However, opaque types do not have a parent (see `gather_explicit_predicates_of`), which means
// that we lose out on the predicates of our actual parent if we dont return those predicates here.
//
//
// fn foo<T: Trait>() -> impl Iterator<Output = Another<{ <T as Trait>::ASSOC }> > { todo!() }
// ^^^^^^^^^^^^^^^^^^^ the def id we are calling
// explicit_predicates_of on
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`.
// However, the anon const cannot inherit predicates from its parent since it's opaque.
//
// To fix this, we call `explicit_predicates_of` directly on `foo`, the parent's parent.
// In the above example this is `foo::{opaque#0}` or `impl Iterator`
let parent_hir_id = tcx.local_def_id_to_hir_id(parent_def_id.def_id);
// In the above example this is the function `foo`
let item_def_id = tcx.hir().get_parent_item(parent_hir_id);
// In the above code example we would be calling `explicit_predicates_of(foo)` here
return tcx.explicit_predicates_of(item_def_id);
}
} }
gather_explicit_predicates_of(tcx, def_id) gather_explicit_predicates_of(tcx, def_id)
} }

View file

@ -137,6 +137,10 @@ hir_typeck_rpit_change_return_type = you could change the return type to be a bo
hir_typeck_rustcall_incorrect_args = hir_typeck_rustcall_incorrect_args =
functions with the "rust-call" ABI must take a single non-self tuple argument functions with the "rust-call" ABI must take a single non-self tuple argument
hir_typeck_self_ctor_from_outer_item = can't reference `Self` constructor from outer item
.label = the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
.suggestion = replace `Self` with the actual type
hir_typeck_struct_expr_non_exhaustive = hir_typeck_struct_expr_non_exhaustive =
cannot create non-exhaustive {$what} using struct expression cannot create non-exhaustive {$what} using struct expression

View file

@ -651,3 +651,31 @@ pub enum SuggestBoxingForReturnImplTrait {
ends: Vec<Span>, ends: Vec<Span>,
}, },
} }
#[derive(Diagnostic)]
#[diag(hir_typeck_self_ctor_from_outer_item, code = E0401)]
pub struct SelfCtorFromOuterItem {
#[primary_span]
pub span: Span,
#[label]
pub impl_span: Span,
#[subdiagnostic]
pub sugg: Option<ReplaceWithName>,
}
#[derive(LintDiagnostic)]
#[diag(hir_typeck_self_ctor_from_outer_item)]
pub struct SelfCtorFromOuterItemLint {
#[label]
pub impl_span: Span,
#[subdiagnostic]
pub sugg: Option<ReplaceWithName>,
}
#[derive(Subdiagnostic)]
#[suggestion(hir_typeck_suggestion, code = "{name}", applicability = "machine-applicable")]
pub struct ReplaceWithName {
#[primary_span]
pub span: Span,
pub name: String,
}

View file

@ -1,5 +1,5 @@
use crate::callee::{self, DeferredCallResolution}; use crate::callee::{self, DeferredCallResolution};
use crate::errors::CtorIsPrivate; use crate::errors::{self, CtorIsPrivate};
use crate::method::{self, MethodCallee, SelfSource}; use crate::method::{self, MethodCallee, SelfSource};
use crate::rvalue_scopes; use crate::rvalue_scopes;
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
@ -21,6 +21,7 @@ use rustc_hir_analysis::hir_ty_lowering::{
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::error::TypeError; use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
@ -1156,6 +1157,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span, span,
tcx.at(span).type_of(impl_def_id).instantiate_identity(), tcx.at(span).type_of(impl_def_id).instantiate_identity(),
); );
// Firstly, check that this SelfCtor even comes from the item we're currently
// typechecking. This can happen because we never validated the resolution of
// SelfCtors, and when we started doing so, we noticed regressions. After
// sufficiently long time, we can remove this check and turn it into a hard
// error in `validate_res_from_ribs` -- it's just difficult to tell whether the
// self type has any generic types during rustc_resolve, which is what we use
// to determine if this is a hard error or warning.
if std::iter::successors(Some(self.body_id.to_def_id()), |def_id| {
self.tcx.generics_of(def_id).parent
})
.all(|def_id| def_id != impl_def_id)
{
let sugg = ty.normalized.ty_adt_def().map(|def| errors::ReplaceWithName {
span: path_span,
name: self.tcx.item_name(def.did()).to_ident_string(),
});
if ty.raw.has_param() {
let guar = self.tcx.dcx().emit_err(errors::SelfCtorFromOuterItem {
span: path_span,
impl_span: tcx.def_span(impl_def_id),
sugg,
});
return (Ty::new_error(self.tcx, guar), res);
} else {
self.tcx.emit_node_span_lint(
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
hir_id,
path_span,
errors::SelfCtorFromOuterItemLint {
impl_span: tcx.def_span(impl_def_id),
sugg,
},
);
}
}
match ty.normalized.ty_adt_def() { match ty.normalized.ty_adt_def() {
Some(adt_def) if adt_def.has_ctor() => { Some(adt_def) if adt_def.has_ctor() => {
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();

View file

@ -235,11 +235,17 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
if let Some(item) = tcx.opt_associated_item(def_id.into()) if let Some(item) = tcx.opt_associated_item(def_id.into())
&& let ty::AssocKind::Const = item.kind && let ty::AssocKind::Const = item.kind
&& let ty::ImplContainer = item.container && let ty::ImplContainer = item.container
&& let Some(trait_item) = item.trait_item_def_id && let Some(trait_item_def_id) = item.trait_item_def_id
{ {
let args = let impl_def_id = item.container_id(tcx);
tcx.impl_trait_ref(item.container_id(tcx)).unwrap().instantiate_identity().args; let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
Some(tcx.type_of(trait_item).instantiate(tcx, args)) let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
tcx,
impl_def_id,
impl_trait_ref.args,
);
tcx.check_args_compatible(trait_item_def_id, args)
.then(|| tcx.type_of(trait_item_def_id).instantiate(tcx, args))
} else { } else {
Some(fcx.next_ty_var(span)) Some(fcx.next_ty_var(span))
} }

View file

@ -381,10 +381,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let maybe_missing_semi = self.check_for_missing_semi(expr, &mut err); let maybe_missing_semi = self.check_for_missing_semi(expr, &mut err);
// We defer to the later error produced by `check_lhs_assignable`. // We defer to the later error produced by `check_lhs_assignable`.
// We only downgrade this if it's the LHS, though. // We only downgrade this if it's the LHS, though, and if this is a
// valid assignment statement.
if maybe_missing_semi if maybe_missing_semi
&& let hir::Node::Expr(parent) = self.tcx.parent_hir_node(expr.hir_id) && let hir::Node::Expr(parent) = self.tcx.parent_hir_node(expr.hir_id)
&& let hir::ExprKind::Assign(lhs, _, _) = parent.kind && let hir::ExprKind::Assign(lhs, _, _) = parent.kind
&& let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(parent.hir_id)
&& let hir::StmtKind::Expr(_) | hir::StmtKind::Semi(_) = stmt.kind
&& lhs.hir_id == expr.hir_id && lhs.hir_id == expr.hir_id
{ {
err.downgrade_to_delayed_bug(); err.downgrade_to_delayed_bug();

View file

@ -116,8 +116,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkPr
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
// Decode the list of work_products // Decode the list of work_products
let Ok(mut work_product_decoder) = let Ok(mut work_product_decoder) = MemDecoder::new(&work_products_data[..], start_pos)
MemDecoder::new(&work_products_data[..], start_pos)
else { else {
sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path }); sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path });
return LoadResult::DataOutOfDate; return LoadResult::DataOutOfDate;

View file

@ -54,17 +54,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
(ty::Param(expected), ty::Param(found)) => { (ty::Param(expected), ty::Param(found)) => {
let generics = tcx.generics_of(body_owner_def_id); let generics = tcx.generics_of(body_owner_def_id);
if let Some(param) = generics.opt_type_param(expected, tcx) { let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
let e_span = tcx.def_span(param.def_id); if !sp.contains(e_span) {
if !sp.contains(e_span) { diag.span_label(e_span, "expected type parameter");
diag.span_label(e_span, "expected type parameter");
}
} }
if let Some(param) = generics.opt_type_param(found, tcx) { let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
let f_span = tcx.def_span(param.def_id); if !sp.contains(f_span) {
if !sp.contains(f_span) { diag.span_label(f_span, "found type parameter");
diag.span_label(f_span, "found type parameter");
}
} }
diag.note( diag.note(
"a type parameter was expected, but a different one was found; \ "a type parameter was expected, but a different one was found; \
@ -87,29 +83,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
| (ty::Alias(ty::Projection, proj), ty::Param(p)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
if !tcx.is_impl_trait_in_trait(proj.def_id) => if !tcx.is_impl_trait_in_trait(proj.def_id) =>
{ {
let parent = tcx let param = tcx.generics_of(body_owner_def_id).type_param(p, tcx);
.generics_of(body_owner_def_id) let p_def_id = param.def_id;
.opt_type_param(p, tcx) let p_span = tcx.def_span(p_def_id);
.and_then(|param| { let expected = match (values.expected.kind(), values.found.kind()) {
let p_def_id = param.def_id; (ty::Param(_), _) => "expected ",
let p_span = tcx.def_span(p_def_id); (_, ty::Param(_)) => "found ",
let expected = match (values.expected.kind(), values.found.kind()) { _ => "",
(ty::Param(_), _) => "expected ", };
(_, ty::Param(_)) => "found ", if !sp.contains(p_span) {
_ => "", diag.span_label(p_span, format!("{expected}this type parameter"));
}; }
if !sp.contains(p_span) { let parent = p_def_id.as_local().and_then(|id| {
diag.span_label( let local_id = tcx.local_def_id_to_hir_id(id);
p_span, let generics = tcx.parent_hir_node(local_id).generics()?;
format!("{expected}this type parameter"), Some((id, generics))
); });
}
p_def_id.as_local().and_then(|id| {
let local_id = tcx.local_def_id_to_hir_id(id);
let generics = tcx.parent_hir_node(local_id).generics()?;
Some((id, generics))
})
});
let mut note = true; let mut note = true;
if let Some((local_id, generics)) = parent { if let Some((local_id, generics)) = parent {
// Synthesize the associated type restriction `Add<Output = Expected>`. // Synthesize the associated type restriction `Add<Output = Expected>`.
@ -183,16 +172,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..)) (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
| (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => { | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
let generics = tcx.generics_of(body_owner_def_id); let generics = tcx.generics_of(body_owner_def_id);
if let Some(param) = generics.opt_type_param(p, tcx) { let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
let p_span = tcx.def_span(param.def_id); let expected = match (values.expected.kind(), values.found.kind()) {
let expected = match (values.expected.kind(), values.found.kind()) { (ty::Param(_), _) => "expected ",
(ty::Param(_), _) => "expected ", (_, ty::Param(_)) => "found ",
(_, ty::Param(_)) => "found ", _ => "",
_ => "", };
}; if !sp.contains(p_span) {
if !sp.contains(p_span) { diag.span_label(p_span, format!("{expected}this type parameter"));
diag.span_label(p_span, format!("{expected}this type parameter"));
}
} }
diag.help("type parameters must be constrained to match other types"); diag.help("type parameters must be constrained to match other types");
if tcx.sess.teach(diag.code.unwrap()) { if tcx.sess.teach(diag.code.unwrap()) {
@ -233,11 +220,9 @@ impl<T> Trait<T> for X {
ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..), ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..),
) => { ) => {
let generics = tcx.generics_of(body_owner_def_id); let generics = tcx.generics_of(body_owner_def_id);
if let Some(param) = generics.opt_type_param(p, tcx) { let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
let p_span = tcx.def_span(param.def_id); if !sp.contains(p_span) {
if !sp.contains(p_span) { diag.span_label(p_span, "expected this type parameter");
diag.span_label(p_span, "expected this type parameter");
}
} }
diag.help(format!( diag.help(format!(
"every closure has a distinct type and so could not always match the \ "every closure has a distinct type and so could not always match the \
@ -246,16 +231,14 @@ impl<T> Trait<T> for X {
} }
(ty::Param(p), _) | (_, ty::Param(p)) => { (ty::Param(p), _) | (_, ty::Param(p)) => {
let generics = tcx.generics_of(body_owner_def_id); let generics = tcx.generics_of(body_owner_def_id);
if let Some(param) = generics.opt_type_param(p, tcx) { let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
let p_span = tcx.def_span(param.def_id); let expected = match (values.expected.kind(), values.found.kind()) {
let expected = match (values.expected.kind(), values.found.kind()) { (ty::Param(_), _) => "expected ",
(ty::Param(_), _) => "expected ", (_, ty::Param(_)) => "found ",
(_, ty::Param(_)) => "found ", _ => "",
_ => "", };
}; if !sp.contains(p_span) {
if !sp.contains(p_span) { diag.span_label(p_span, format!("{expected}this type parameter"));
diag.span_label(p_span, format!("{expected}this type parameter"));
}
} }
} }
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
@ -545,10 +528,8 @@ impl<T> Trait<T> for X {
return false; return false;
}; };
let generics = tcx.generics_of(body_owner_def_id); let generics = tcx.generics_of(body_owner_def_id);
let Some(param) = generics.opt_type_param(param_ty, tcx) else { let def_id = generics.type_param(param_ty, tcx).def_id;
return false; let Some(def_id) = def_id.as_local() else {
};
let Some(def_id) = param.def_id.as_local() else {
return false; return false;
}; };

View file

@ -957,27 +957,14 @@ impl<'tcx> InferCtxt<'tcx> {
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
return Err((a_vid, b_vid)); return Err((a_vid, b_vid));
} }
// We don't silently want to constrain hidden types here, so we assert that either one side is
// an infer var, so it'll get constrained to whatever the other side is, or there are no opaque
// types involved.
// We don't expect this to actually get hit, but if it does, we now at least know how to write
// a test for it.
(_, ty::Infer(ty::TyVar(_))) => {}
(ty::Infer(ty::TyVar(_)), _) => {}
_ if r_a != r_b && (r_a, r_b).has_opaque_types() => {
span_bug!(
cause.span(),
"opaque types got hidden types registered from within subtype predicate: {r_a:?} vs {r_b:?}"
)
}
_ => {} _ => {}
} }
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| { self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
if a_is_expected { if a_is_expected {
Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b))
} else { } else {
Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a)) Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a))
} }
}) })
} }

View file

@ -62,7 +62,9 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
}; };
let (article, ty, var) = match adt.did() { let (article, ty, var) = match adt.did() {
did if cx.tcx.is_diagnostic_item(sym::Option, did) && ref_mutability.is_some() => ("a", "Option", "Some"), did if cx.tcx.is_diagnostic_item(sym::Option, did) && ref_mutability.is_some() => {
("a", "Option", "Some")
}
did if cx.tcx.is_diagnostic_item(sym::Option, did) => ("an", "Option", "Some"), did if cx.tcx.is_diagnostic_item(sym::Option, did) => ("an", "Option", "Some"),
did if cx.tcx.is_diagnostic_item(sym::Result, did) => ("a", "Result", "Ok"), did if cx.tcx.is_diagnostic_item(sym::Result, did) => ("a", "Result", "Ok"),
_ => return, _ => return,

View file

@ -90,6 +90,7 @@ declare_lint_pass! {
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
RUST_2021_PRELUDE_COLLISIONS, RUST_2021_PRELUDE_COLLISIONS,
RUST_2024_INCOMPATIBLE_PAT, RUST_2024_INCOMPATIBLE_PAT,
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
SINGLE_USE_LIFETIMES, SINGLE_USE_LIFETIMES,
SOFT_UNSTABLE, SOFT_UNSTABLE,
@ -3149,6 +3150,47 @@ declare_lint! {
"detects `#[unstable]` on stable trait implementations for stable types" "detects `#[unstable]` on stable trait implementations for stable types"
} }
declare_lint! {
/// The `self_constructor_from_outer_item` lint detects cases where the `Self` constructor
/// was silently allowed due to a bug in the resolver, and which may produce surprising
/// and unintended behavior.
///
/// Using a `Self` type alias from an outer item was never intended, but was silently allowed.
/// This is deprecated -- and is a hard error when the `Self` type alias references generics
/// that are not in scope.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(self_constructor_from_outer_item)]
///
/// struct S0(usize);
///
/// impl S0 {
/// fn foo() {
/// const C: S0 = Self(0);
/// fn bar() -> S0 {
/// Self(0)
/// }
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The `Self` type alias should not be reachable because nested items are not associated with
/// the scope of the parameters from the parent item.
pub SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
Warn,
"detect unsupported use of `Self` from outer item",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
reference: "issue #124186 <https://github.com/rust-lang/rust/issues/124186>",
};
}
declare_lint! { declare_lint! {
/// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons /// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons
/// in macro bodies when the macro is invoked in expression position. /// in macro bodies when the macro is invoked in expression position.

View file

@ -245,20 +245,6 @@ impl<'tcx> Generics {
} }
} }
/// Returns the `GenericParamDef` with the given index if available.
pub fn opt_param_at(
&'tcx self,
param_index: usize,
tcx: TyCtxt<'tcx>,
) -> Option<&'tcx GenericParamDef> {
if let Some(index) = param_index.checked_sub(self.parent_count) {
self.own_params.get(index)
} else {
tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
.opt_param_at(param_index, tcx)
}
}
pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] { pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] {
if let Some(index) = param_index.checked_sub(self.parent_count) { if let Some(index) = param_index.checked_sub(self.parent_count) {
&self.own_params[..index] &self.own_params[..index]
@ -290,20 +276,6 @@ impl<'tcx> Generics {
} }
} }
/// Returns the `GenericParamDef` associated with this `ParamTy` if it belongs to this
/// `Generics`.
pub fn opt_type_param(
&'tcx self,
param: ParamTy,
tcx: TyCtxt<'tcx>,
) -> Option<&'tcx GenericParamDef> {
let param = self.opt_param_at(param.index as usize, tcx)?;
match param.kind {
GenericParamDefKind::Type { .. } => Some(param),
_ => None,
}
}
/// Returns the `GenericParamDef` associated with this `ParamConst`. /// Returns the `GenericParamDef` associated with this `ParamConst`.
pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
let param = self.param_at(param.index as usize, tcx); let param = self.param_at(param.index as usize, tcx);

View file

@ -16,6 +16,7 @@ rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" } rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_macros = { path = "../rustc_macros" } rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" } rustc_middle = { path = "../rustc_middle" }
rustc_mir_build = { path = "../rustc_mir_build" } rustc_mir_build = { path = "../rustc_mir_build" }

View file

@ -1,7 +1,6 @@
//! Inlining pass for MIR functions //! Inlining pass for MIR functions
use crate::deref_separator::deref_finder; use crate::deref_separator::deref_finder;
use rustc_attr::InlineAttr; use rustc_attr::InlineAttr;
use rustc_const_eval::transform::validate::validate_types;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
@ -21,6 +20,7 @@ use rustc_target::spec::abi::Abi;
use crate::cost_checker::CostChecker; use crate::cost_checker::CostChecker;
use crate::simplify::simplify_cfg; use crate::simplify::simplify_cfg;
use crate::util; use crate::util;
use crate::validate::validate_types;
use std::iter; use std::iter;
use std::ops::{Range, RangeFrom}; use std::ops::{Range, RangeFrom};

View file

@ -109,9 +109,9 @@ mod simplify_comparison_integral;
mod sroa; mod sroa;
mod unreachable_enum_branching; mod unreachable_enum_branching;
mod unreachable_prop; mod unreachable_prop;
mod validate;
use rustc_const_eval::transform::check_consts::{self, ConstCx}; use rustc_const_eval::check_consts::{self, ConstCx};
use rustc_const_eval::transform::validate;
use rustc_mir_dataflow::rustc_peek; use rustc_mir_dataflow::rustc_peek;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" } rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

View file

@ -30,7 +30,7 @@ use std::assert_matches::assert_matches;
use std::cell::Cell; use std::cell::Cell;
use std::{cmp, iter, mem}; use std::{cmp, iter, mem};
use rustc_const_eval::transform::check_consts::{qualifs, ConstCx}; use rustc_const_eval::check_consts::{qualifs, ConstCx};
/// A `MirPass` for promotion. /// A `MirPass` for promotion.
/// ///

View file

@ -685,6 +685,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
check_equal(self, location, *f_ty); check_equal(self, location, *f_ty);
} }
ty::Adt(adt_def, args) => { ty::Adt(adt_def, args) => {
// see <https://github.com/rust-lang/rust/blob/7601adcc764d42c9f2984082b49948af652df986/compiler/rustc_middle/src/ty/layout.rs#L861-L864>
if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() {
self.fail(
location,
format!("You can't project to field {f:?} of `DynMetadata` because \
layout is weird and thinks it doesn't have fields."),
);
}
let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT); let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT);
let Some(field) = adt_def.variant(var).fields.get(f) else { let Some(field) = adt_def.variant(var).fields.get(f) else {
fail_out_of_bounds(self, location); fail_out_of_bounds(self, location);

View file

@ -44,7 +44,7 @@ fn ascii_escapes(b: &mut Bencher) {
assert_fmt( assert_fmt(
s, s,
r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#, r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#,
21, 15,
); );
b.iter(|| { b.iter(|| {
black_box(format!("{:?}", black_box(s))); black_box(format!("{:?}", black_box(s)));
@ -72,7 +72,7 @@ fn mostly_unicode(b: &mut Bencher) {
#[bench] #[bench]
fn mixed(b: &mut Bencher) { fn mixed(b: &mut Bencher) {
let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\"."; let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\".";
assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 36); assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 21);
b.iter(|| { b.iter(|| {
black_box(format!("{:?}", black_box(s))); black_box(format!("{:?}", black_box(s)));
}); });

View file

@ -898,6 +898,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
/// assert_eq!(2.clamp(-2, 1), 1); /// assert_eq!(2.clamp(-2, 1), 1);
/// ``` /// ```
#[must_use] #[must_use]
#[inline]
#[stable(feature = "clamp", since = "1.50.0")] #[stable(feature = "clamp", since = "1.50.0")]
fn clamp(self, min: Self, max: Self) -> Self fn clamp(self, min: Self, max: Self) -> Self
where where

View file

@ -2402,23 +2402,47 @@ impl Display for bool {
impl Debug for str { impl Debug for str {
fn fmt(&self, f: &mut Formatter<'_>) -> Result { fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.write_char('"')?; f.write_char('"')?;
let mut from = 0;
for (i, c) in self.char_indices() { // substring we know is printable
let esc = c.escape_debug_ext(EscapeDebugExtArgs { let mut printable_range = 0..0;
escape_grapheme_extended: true,
escape_single_quote: false, fn needs_escape(b: u8) -> bool {
escape_double_quote: true, b > 0x7E || b < 0x20 || b == b'\\' || b == b'"'
});
// If char needs escaping, flush backlog so far and write, else skip
if esc.len() != 1 {
f.write_str(&self[from..i])?;
for c in esc {
f.write_char(c)?;
}
from = i + c.len_utf8();
}
} }
f.write_str(&self[from..])?;
// the loop here first skips over runs of printable ASCII as a fast path.
// other chars (unicode, or ASCII that needs escaping) are then handled per-`char`.
let mut rest = self;
while rest.len() > 0 {
let Some(non_printable_start) = rest.as_bytes().iter().position(|&b| needs_escape(b))
else {
printable_range.end += rest.len();
break;
};
printable_range.end += non_printable_start;
// SAFETY: the position was derived from an iterator, so is known to be within bounds, and at a char boundary
rest = unsafe { rest.get_unchecked(non_printable_start..) };
let mut chars = rest.chars();
if let Some(c) = chars.next() {
let esc = c.escape_debug_ext(EscapeDebugExtArgs {
escape_grapheme_extended: true,
escape_single_quote: false,
escape_double_quote: true,
});
if esc.len() != 1 {
f.write_str(&self[printable_range.clone()])?;
Display::fmt(&esc, f)?;
printable_range.start = printable_range.end + c.len_utf8();
}
printable_range.end += c.len_utf8();
}
rest = chars.as_str();
}
f.write_str(&self[printable_range])?;
f.write_char('"') f.write_char('"')
} }
} }
@ -2434,13 +2458,12 @@ impl Display for str {
impl Debug for char { impl Debug for char {
fn fmt(&self, f: &mut Formatter<'_>) -> Result { fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.write_char('\'')?; f.write_char('\'')?;
for c in self.escape_debug_ext(EscapeDebugExtArgs { let esc = self.escape_debug_ext(EscapeDebugExtArgs {
escape_grapheme_extended: true, escape_grapheme_extended: true,
escape_single_quote: true, escape_single_quote: true,
escape_double_quote: false, escape_double_quote: false,
}) { });
f.write_char(c)? Display::fmt(&esc, f)?;
}
f.write_char('\'') f.write_char('\'')
} }
} }

View file

@ -152,7 +152,7 @@ extern "rust-intrinsic" {
#[rustc_nounwind] #[rustc_nounwind]
pub fn simd_fabs<T>(x: T) -> T; pub fn simd_fabs<T>(x: T) -> T;
/// Elementwise minimum of a vector. /// Elementwise minimum of two vectors.
/// ///
/// `T` must be a vector of floating-point primitive types. /// `T` must be a vector of floating-point primitive types.
/// ///
@ -160,7 +160,7 @@ extern "rust-intrinsic" {
#[rustc_nounwind] #[rustc_nounwind]
pub fn simd_fmin<T>(x: T, y: T) -> T; pub fn simd_fmin<T>(x: T, y: T) -> T;
/// Elementwise maximum of a vector. /// Elementwise maximum of two vectors.
/// ///
/// `T` must be a vector of floating-point primitive types. /// `T` must be a vector of floating-point primitive types.
/// ///
@ -387,7 +387,7 @@ extern "rust-intrinsic" {
#[rustc_nounwind] #[rustc_nounwind]
pub fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U; pub fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U;
/// Add elements within a vector in arbitrary order. May also be re-associated with /// Multiply elements within a vector in arbitrary order. May also be re-associated with
/// unordered additions on the inputs/outputs. /// unordered additions on the inputs/outputs.
/// ///
/// `T` must be a vector of integer or floating-point primitive types. /// `T` must be a vector of integer or floating-point primitive types.
@ -405,7 +405,7 @@ extern "rust-intrinsic" {
#[rustc_nounwind] #[rustc_nounwind]
pub fn simd_reduce_all<T>(x: T) -> bool; pub fn simd_reduce_all<T>(x: T) -> bool;
/// Check if all mask values are true. /// Check if any mask value is true.
/// ///
/// `T` must be a vector of integer primitive types. /// `T` must be a vector of integer primitive types.
/// ///

View file

@ -178,8 +178,8 @@ impl<T: ?Sized> Clone for PtrComponents<T> {
/// compare equal (since identical vtables can be deduplicated within a codegen unit). /// compare equal (since identical vtables can be deduplicated within a codegen unit).
#[lang = "dyn_metadata"] #[lang = "dyn_metadata"]
pub struct DynMetadata<Dyn: ?Sized> { pub struct DynMetadata<Dyn: ?Sized> {
vtable_ptr: &'static VTable, _vtable_ptr: &'static VTable,
phantom: crate::marker::PhantomData<Dyn>, _phantom: crate::marker::PhantomData<Dyn>,
} }
extern "C" { extern "C" {
@ -191,6 +191,17 @@ extern "C" {
} }
impl<Dyn: ?Sized> DynMetadata<Dyn> { impl<Dyn: ?Sized> DynMetadata<Dyn> {
/// One of the things that rustc_middle does with this being a lang item is
/// give it `FieldsShape::Primitive`, which means that as far as codegen can
/// tell, it *is* a reference, and thus doesn't have any fields.
/// That means we can't use field access, and have to transmute it instead.
#[inline]
fn vtable_ptr(self) -> *const VTable {
// SAFETY: this layout assumption is hard-coded into the compiler.
// If it's somehow not a size match, the transmute will error.
unsafe { crate::mem::transmute::<Self, &'static VTable>(self) }
}
/// Returns the size of the type associated with this vtable. /// Returns the size of the type associated with this vtable.
#[inline] #[inline]
pub fn size_of(self) -> usize { pub fn size_of(self) -> usize {
@ -199,7 +210,7 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
// `Send` part! // `Send` part!
// SAFETY: DynMetadata always contains a valid vtable pointer // SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe { return unsafe {
crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ()) crate::intrinsics::vtable_size(self.vtable_ptr() as *const ())
}; };
} }
@ -208,7 +219,7 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
pub fn align_of(self) -> usize { pub fn align_of(self) -> usize {
// SAFETY: DynMetadata always contains a valid vtable pointer // SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe { return unsafe {
crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ()) crate::intrinsics::vtable_align(self.vtable_ptr() as *const ())
}; };
} }
@ -226,7 +237,7 @@ unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> { impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish() f.debug_tuple("DynMetadata").field(&self.vtable_ptr()).finish()
} }
} }
@ -248,7 +259,7 @@ impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> { impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
#[inline] #[inline]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr) crate::ptr::eq::<VTable>(self.vtable_ptr(), other.vtable_ptr())
} }
} }
@ -256,7 +267,7 @@ impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
#[inline] #[inline]
#[allow(ambiguous_wide_pointer_comparisons)] #[allow(ambiguous_wide_pointer_comparisons)]
fn cmp(&self, other: &Self) -> crate::cmp::Ordering { fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
(self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable)) <*const VTable>::cmp(&self.vtable_ptr(), &other.vtable_ptr())
} }
} }
@ -270,6 +281,6 @@ impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> { impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
#[inline] #[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) { fn hash<H: Hasher>(&self, hasher: &mut H) {
crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher) crate::ptr::hash::<VTable, _>(self.vtable_ptr(), hasher)
} }
} }

View file

@ -9,8 +9,6 @@ pub mod cmath;
pub mod os_str; pub mod os_str;
pub mod path; pub mod path;
pub mod sync; pub mod sync;
#[allow(dead_code)]
#[allow(unused_imports)]
pub mod thread_local; pub mod thread_local;
// FIXME(117276): remove this, move feature implementations into individual // FIXME(117276): remove this, move feature implementations into individual

View file

@ -1,6 +1,5 @@
use crate::cell::UnsafeCell; use crate::cell::UnsafeCell;
use crate::hint::unreachable_unchecked; use crate::hint::unreachable_unchecked;
use crate::mem::forget;
use crate::ptr; use crate::ptr;
use crate::sys::thread_local::abort_on_dtor_unwind; use crate::sys::thread_local::abort_on_dtor_unwind;
use crate::sys::thread_local_dtor::register_dtor; use crate::sys::thread_local_dtor::register_dtor;

View file

@ -1,4 +1,5 @@
#![unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")] #![unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
#![cfg_attr(test, allow(unused))]
// There are three thread-local implementations: "static", "fast", "OS". // There are three thread-local implementations: "static", "fast", "OS".
// The "OS" thread local key type is accessed via platform-specific API calls and is slow, while the // The "OS" thread local key type is accessed via platform-specific API calls and is slow, while the
@ -24,94 +25,12 @@ cfg_if::cfg_if! {
} }
} }
// Not used by the fast-local TLS anymore.
// FIXME(#110897): remove this.
#[allow(unused)]
mod lazy {
use crate::cell::UnsafeCell;
use crate::hint;
use crate::mem;
pub struct LazyKeyInner<T> {
inner: UnsafeCell<Option<T>>,
}
impl<T> LazyKeyInner<T> {
pub const fn new() -> LazyKeyInner<T> {
LazyKeyInner { inner: UnsafeCell::new(None) }
}
pub unsafe fn get(&self) -> Option<&'static T> {
// SAFETY: The caller must ensure no reference is ever handed out to
// the inner cell nor mutable reference to the Option<T> inside said
// cell. This make it safe to hand a reference, though the lifetime
// of 'static is itself unsafe, making the get method unsafe.
unsafe { (*self.inner.get()).as_ref() }
}
/// The caller must ensure that no reference is active: this method
/// needs unique access.
pub unsafe fn initialize<F: FnOnce() -> T>(&self, init: F) -> &'static T {
// Execute the initialization up front, *then* move it into our slot,
// just in case initialization fails.
let value = init();
let ptr = self.inner.get();
// SAFETY:
//
// note that this can in theory just be `*ptr = Some(value)`, but due to
// the compiler will currently codegen that pattern with something like:
//
// ptr::drop_in_place(ptr)
// ptr::write(ptr, Some(value))
//
// Due to this pattern it's possible for the destructor of the value in
// `ptr` (e.g., if this is being recursively initialized) to re-access
// TLS, in which case there will be a `&` and `&mut` pointer to the same
// value (an aliasing violation). To avoid setting the "I'm running a
// destructor" flag we just use `mem::replace` which should sequence the
// operations a little differently and make this safe to call.
//
// The precondition also ensures that we are the only one accessing
// `self` at the moment so replacing is fine.
unsafe {
let _ = mem::replace(&mut *ptr, Some(value));
}
// SAFETY: With the call to `mem::replace` it is guaranteed there is
// a `Some` behind `ptr`, not a `None` so `unreachable_unchecked`
// will never be reached.
unsafe {
// After storing `Some` we want to get a reference to the contents of
// what we just stored. While we could use `unwrap` here and it should
// always work it empirically doesn't seem to always get optimized away,
// which means that using something like `try_with` can pull in
// panicking code and cause a large size bloat.
match *ptr {
Some(ref x) => x,
None => hint::unreachable_unchecked(),
}
}
}
/// Watch out: unsynchronized internal mutability!
///
/// # Safety
/// Causes UB if any reference to the value is used after this.
#[allow(unused)]
pub(crate) unsafe fn take(&self) -> Option<T> {
let mutable: *mut _ = UnsafeCell::get(&self.inner);
// SAFETY: That's the caller's problem.
unsafe { mutable.replace(None) }
}
}
}
/// Run a callback in a scenario which must not unwind (such as a `extern "C" /// Run a callback in a scenario which must not unwind (such as a `extern "C"
/// fn` declared in a user crate). If the callback unwinds anyway, then /// fn` declared in a user crate). If the callback unwinds anyway, then
/// `rtabort` with a message about thread local panicking on drop. /// `rtabort` with a message about thread local panicking on drop.
#[inline] #[inline]
pub fn abort_on_dtor_unwind(f: impl FnOnce()) { #[allow(dead_code)]
fn abort_on_dtor_unwind(f: impl FnOnce()) {
// Using a guard like this is lower cost. // Using a guard like this is lower cost.
let guard = DtorUnwindGuard; let guard = DtorUnwindGuard;
f(); f();

View file

@ -1,7 +1,8 @@
use super::lazy::LazyKeyInner; use super::abort_on_dtor_unwind;
use crate::cell::Cell; use crate::cell::Cell;
use crate::sys_common::thread_local_key::StaticKey as OsStaticKey; use crate::marker::PhantomData;
use crate::{fmt, marker, panic, ptr}; use crate::ptr;
use crate::sys_common::thread_local_key::StaticKey as OsKey;
#[doc(hidden)] #[doc(hidden)]
#[allow_internal_unstable(thread_local_internals)] #[allow_internal_unstable(thread_local_internals)]
@ -10,38 +11,9 @@ use crate::{fmt, marker, panic, ptr};
#[rustc_macro_transparency = "semitransparent"] #[rustc_macro_transparency = "semitransparent"]
pub macro thread_local_inner { pub macro thread_local_inner {
// used to generate the `LocalKey` value for const-initialized thread locals // used to generate the `LocalKey` value for const-initialized thread locals
(@key $t:ty, const $init:expr) => {{ (@key $t:ty, const $init:expr) => {
#[inline] $crate::thread::local_impl::thread_local_inner!(@key $t, { const INIT_EXPR: $t = $init; INIT_EXPR })
#[deny(unsafe_op_in_unsafe_fn)] },
unsafe fn __getit(
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
) -> $crate::option::Option<&'static $t> {
const INIT_EXPR: $t = $init;
// On platforms without `#[thread_local]` we fall back to the
// same implementation as below for os thread locals.
#[inline]
const fn __init() -> $t { INIT_EXPR }
static __KEY: $crate::thread::local_impl::Key<$t> =
$crate::thread::local_impl::Key::new();
unsafe {
__KEY.get(move || {
if let $crate::option::Option::Some(init) = _init {
if let $crate::option::Option::Some(value) = init.take() {
return value;
} else if $crate::cfg!(debug_assertions) {
$crate::unreachable!("missing initial value");
}
}
__init()
})
}
}
unsafe {
$crate::thread::LocalKey::new(__getit)
}
}},
// used to generate the `LocalKey` value for `thread_local!` // used to generate the `LocalKey` value for `thread_local!`
(@key $t:ty, $init:expr) => { (@key $t:ty, $init:expr) => {
@ -55,20 +27,11 @@ pub macro thread_local_inner {
unsafe fn __getit( unsafe fn __getit(
init: $crate::option::Option<&mut $crate::option::Option<$t>>, init: $crate::option::Option<&mut $crate::option::Option<$t>>,
) -> $crate::option::Option<&'static $t> { ) -> $crate::option::Option<&'static $t> {
static __KEY: $crate::thread::local_impl::Key<$t> = use $crate::thread::local_impl::Key;
$crate::thread::local_impl::Key::new();
static __KEY: Key<$t> = Key::new();
unsafe { unsafe {
__KEY.get(move || { __KEY.get(init, __init)
if let $crate::option::Option::Some(init) = init {
if let $crate::option::Option::Some(value) = init.take() {
return value;
} else if $crate::cfg!(debug_assertions) {
$crate::unreachable!("missing default value");
}
}
__init()
})
} }
} }
@ -85,78 +48,78 @@ pub macro thread_local_inner {
/// Use a regular global static to store this key; the state provided will then be /// Use a regular global static to store this key; the state provided will then be
/// thread-local. /// thread-local.
#[allow(missing_debug_implementations)]
pub struct Key<T> { pub struct Key<T> {
// OS-TLS key that we'll use to key off. os: OsKey,
os: OsStaticKey, marker: PhantomData<Cell<T>>,
marker: marker::PhantomData<Cell<T>>,
}
impl<T> fmt::Debug for Key<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Key").finish_non_exhaustive()
}
} }
unsafe impl<T> Sync for Key<T> {} unsafe impl<T> Sync for Key<T> {}
struct Value<T: 'static> { struct Value<T: 'static> {
inner: LazyKeyInner<T>, value: T,
key: &'static Key<T>, key: &'static Key<T>,
} }
impl<T: 'static> Key<T> { impl<T: 'static> Key<T> {
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
pub const fn new() -> Key<T> { pub const fn new() -> Key<T> {
Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData } Key { os: OsKey::new(Some(destroy_value::<T>)), marker: PhantomData }
} }
/// It is a requirement for the caller to ensure that no mutable /// Get the value associated with this key, initializating it if necessary.
/// reference is active when this method is called. ///
pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> { /// # Safety
// SAFETY: See the documentation for this method. /// * the returned reference must not be used after recursive initialization
/// or thread destruction occurs.
pub unsafe fn get(
&'static self,
i: Option<&mut Option<T>>,
f: impl FnOnce() -> T,
) -> Option<&'static T> {
// SAFETY: (FIXME: get should actually be safe)
let ptr = unsafe { self.os.get() as *mut Value<T> }; let ptr = unsafe { self.os.get() as *mut Value<T> };
if ptr.addr() > 1 { if ptr.addr() > 1 {
// SAFETY: the check ensured the pointer is safe (its destructor // SAFETY: the check ensured the pointer is safe (its destructor
// is not running) + it is coming from a trusted source (self). // is not running) + it is coming from a trusted source (self).
if let Some(ref value) = unsafe { (*ptr).inner.get() } { unsafe { Some(&(*ptr).value) }
return Some(value); } else {
} // SAFETY: At this point we are sure we have no value and so
// initializing (or trying to) is safe.
unsafe { self.try_initialize(ptr, i, f) }
} }
// SAFETY: At this point we are sure we have no value and so
// initializing (or trying to) is safe.
unsafe { self.try_initialize(init) }
} }
// `try_initialize` is only called once per os thread local variable, unsafe fn try_initialize(
// except in corner cases where thread_local dtors reference other &'static self,
// thread_local's, or it is being recursively initialized. ptr: *mut Value<T>,
unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> { i: Option<&mut Option<T>>,
// SAFETY: No mutable references are ever handed out meaning getting f: impl FnOnce() -> T,
// the value is ok. ) -> Option<&'static T> {
let ptr = unsafe { self.os.get() as *mut Value<T> };
if ptr.addr() == 1 { if ptr.addr() == 1 {
// destructor is running // destructor is running
return None; return None;
} }
let ptr = if ptr.is_null() { let value = i.and_then(Option::take).unwrap_or_else(f);
// If the lookup returned null, we haven't initialized our own let ptr = Box::into_raw(Box::new(Value { value, key: self }));
// local copy, so do that now. // SAFETY: (FIXME: get should actually be safe)
let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self })); let old = unsafe { self.os.get() as *mut Value<T> };
// SAFETY: At this point we are sure there is no value inside // SAFETY: `ptr` is a correct pointer that can be destroyed by the key destructor.
// ptr so setting it will not affect anyone else. unsafe {
unsafe { self.os.set(ptr as *mut u8);
self.os.set(ptr as *mut u8); }
} if !old.is_null() {
ptr // If the variable was recursively initialized, drop the old value.
} else { // SAFETY: We cannot be inside a `LocalKey::with` scope, as the
// recursive initialization // initializer has already returned and the next scope only starts
ptr // after we return the pointer. Therefore, there can be no references
}; // to the old value.
drop(unsafe { Box::from_raw(old) });
}
// SAFETY: ptr has been ensured as non-NUL just above an so can be // SAFETY: We just created this value above.
// dereferenced safely. unsafe { Some(&(*ptr).value) }
unsafe { Some((*ptr).inner.initialize(init)) }
} }
} }
@ -170,16 +133,11 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
// //
// Note that to prevent an infinite loop we reset it back to null right // Note that to prevent an infinite loop we reset it back to null right
// before we return from the destructor ourselves. // before we return from the destructor ourselves.
// abort_on_dtor_unwind(|| {
// Wrap the call in a catch to ensure unwinding is caught in the event let ptr = unsafe { Box::from_raw(ptr as *mut Value<T>) };
// a panic takes place in a destructor.
if let Err(_) = panic::catch_unwind(|| unsafe {
let ptr = Box::from_raw(ptr as *mut Value<T>);
let key = ptr.key; let key = ptr.key;
key.os.set(ptr::without_provenance_mut(1)); unsafe { key.os.set(ptr::without_provenance_mut(1)) };
drop(ptr); drop(ptr);
key.os.set(ptr::null_mut()); unsafe { key.os.set(ptr::null_mut()) };
}) { });
rtabort!("thread local panicked on drop");
}
} }

View file

@ -98,7 +98,7 @@ fn fmt_thousands_sep(mut n: f64, sep: char) -> String {
(0, true) => write!(output, "{:06.2}", n / base as f64).unwrap(), (0, true) => write!(output, "{:06.2}", n / base as f64).unwrap(),
(0, false) => write!(output, "{:.2}", n / base as f64).unwrap(), (0, false) => write!(output, "{:.2}", n / base as f64).unwrap(),
(_, true) => write!(output, "{:03}", n as usize / base).unwrap(), (_, true) => write!(output, "{:03}", n as usize / base).unwrap(),
_ => write!(output, "{}", n as usize / base).unwrap() _ => write!(output, "{}", n as usize / base).unwrap(),
} }
if pow != 0 { if pow != 0 {
output.push(sep); output.push(sep);

View file

@ -6,7 +6,7 @@ and some of the technical details of the build system.
Note that this README only covers internal information, not how to use the tool. Note that this README only covers internal information, not how to use the tool.
Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information. Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information.
[bootstrapping-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/bootstrapping.html [bootstrapping-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/bootstrapping/intro.html
## Introduction ## Introduction

View file

@ -60,7 +60,14 @@ fn check_cli<const N: usize>(paths: [&str; N]) {
macro_rules! std { macro_rules! std {
($host:ident => $target:ident, stage = $stage:literal) => { ($host:ident => $target:ident, stage = $stage:literal) => {
compile::Std::new( compile::Std::new(
Compiler { host: TargetSelection::from_user(concat!(stringify!($host), "-", stringify!($host))), stage: $stage }, Compiler {
host: TargetSelection::from_user(concat!(
stringify!($host),
"-",
stringify!($host)
)),
stage: $stage,
},
TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))), TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))),
) )
}; };
@ -83,7 +90,14 @@ macro_rules! doc_std {
macro_rules! rustc { macro_rules! rustc {
($host:ident => $target:ident, stage = $stage:literal) => { ($host:ident => $target:ident, stage = $stage:literal) => {
compile::Rustc::new( compile::Rustc::new(
Compiler { host: TargetSelection::from_user(concat!(stringify!($host), "-", stringify!($host))), stage: $stage }, Compiler {
host: TargetSelection::from_user(concat!(
stringify!($host),
"-",
stringify!($host)
)),
stage: $stage,
},
TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))), TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))),
) )
}; };
@ -141,10 +155,14 @@ fn check_missing_paths_for_x_test_tests() {
// Skip if not a test directory. // Skip if not a test directory.
if path.ends_with("tests/auxiliary") || !path.is_dir() { if path.ends_with("tests/auxiliary") || !path.is_dir() {
continue continue;
} }
assert!(tests_remap_paths.iter().any(|item| path.ends_with(*item)), "{} is missing in PATH_REMAP tests list.", path.display()); assert!(
tests_remap_paths.iter().any(|item| path.ends_with(*item)),
"{} is missing in PATH_REMAP tests list.",
path.display()
);
} }
} }
@ -185,7 +203,8 @@ fn alias_and_path_for_library() {
&[std!(A => A, stage = 0), std!(A => A, stage = 1)] &[std!(A => A, stage = 0), std!(A => A, stage = 1)]
); );
let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A-A"], &["A-A"])); let mut cache =
run_build(&["library".into(), "core".into()], configure("doc", &["A-A"], &["A-A"]));
assert_eq!(first(cache.all::<doc::Std>()), &[doc_std!(A => A, stage = 0)]); assert_eq!(first(cache.all::<doc::Std>()), &[doc_std!(A => A, stage = 0)]);
} }

View file

@ -199,11 +199,15 @@ than building it.
if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) { if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) {
let mut has_target = false; let mut has_target = false;
let missing_targets_hashset: HashSet<_> = STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect(); let missing_targets_hashset: HashSet<_> =
let duplicated_targets: Vec<_> = stage0_supported_target_list.intersection(&missing_targets_hashset).collect(); STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect();
let duplicated_targets: Vec<_> =
stage0_supported_target_list.intersection(&missing_targets_hashset).collect();
if !duplicated_targets.is_empty() { if !duplicated_targets.is_empty() {
println!("Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list."); println!(
"Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list."
);
for duplicated_target in duplicated_targets { for duplicated_target in duplicated_targets {
println!(" {duplicated_target}"); println!(" {duplicated_target}");
} }

View file

@ -1,5 +1,5 @@
pub mod ci; pub mod ci;
pub mod git; pub mod git;
pub mod metrics; pub mod metrics;
pub mod util;
pub mod stage0_parser; pub mod stage0_parser;
pub mod util;

View file

@ -6,7 +6,7 @@
use clippy_config::msrvs::{self, Msrv}; use clippy_config::msrvs::{self, Msrv};
use hir::LangItem; use hir::LangItem;
use rustc_attr::StableSince; use rustc_attr::StableSince;
use rustc_const_eval::transform::check_consts::ConstCx; use rustc_const_eval::check_consts::ConstCx;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;

View file

@ -1 +1 @@
78dd504f2fd87c0cfabff7d9174253411caf2f80 21e6de7eb64c09102de3f100420a09edc1a2a8d7

View file

@ -1,4 +1,4 @@
thread 'rustc' panicked at compiler/rustc_const_eval/src/transform/validate.rs:LL:CC: thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:
broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]: broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
(*(_2.0: *mut i32)), has deref at the wrong place (*(_2.0: *mut i32)), has deref at the wrong place
stack backtrace: stack backtrace:

View file

@ -228,7 +228,6 @@ run-make/rmeta-preferred/Makefile
run-make/rustc-macro-dep-files/Makefile run-make/rustc-macro-dep-files/Makefile
run-make/rustdoc-io-error/Makefile run-make/rustdoc-io-error/Makefile
run-make/rustdoc-verify-output-files/Makefile run-make/rustdoc-verify-output-files/Makefile
run-make/rustdoc-with-output-option/Makefile
run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-cdylib-link/Makefile
run-make/sanitizer-dylib-link/Makefile run-make/sanitizer-dylib-link/Makefile
run-make/sanitizer-staticlib-link/Makefile run-make/sanitizer-staticlib-link/Makefile

View file

@ -1,8 +0,0 @@
//@ known-bug: #118403
#![feature(generic_const_exprs)]
pub struct X<const N: usize> {}
impl<const Z: usize> X<Z> {
pub fn y<'a, U: 'a>(&'a self) -> impl Iterator<Item = impl Iterator<Item = [u8; Z]> + '_> {
(0..1).map(move |_| (0..1).map(move |_| loop {}))
}
}

View file

@ -1,8 +0,0 @@
//@ known-bug: #121574
#![feature(generic_const_exprs)]
pub struct DimName<const N: usize> {}
impl<const Z: usize> X<Z> {
pub fn y<'a, U: 'a>(&'a self) -> impl Iterator<Item = impl Iterator<Item = [u8; Z]> + '_> {
"0".as_bytes(move |_| (0..1).map(move |_| loop {}))
}
}

View file

@ -1,6 +0,0 @@
//@ known-bug: #121574
#![feature(generic_const_exprs)]
impl<const Z: usize> X<Z> {
pub fn y<'a, U: 'a>(&'a self) -> impl Iterator<Item = impl Iterator<Item = [u8; Z]> + '_> {}
}

View file

@ -1,10 +0,0 @@
//@ known-bug: rust-lang/rust#124833
#![feature(generic_const_items)]
trait Trait {
const C<'a>: &'a str;
}
impl Trait for () {
const C<'a>: = "C";
}

View file

@ -1,22 +0,0 @@
//@ known-bug: rust-lang/rust#124891
type Tait = impl FnOnce() -> ();
fn reify_as_tait() -> Thunk<Tait> {
Thunk::new(|cont| cont)
}
struct Thunk<F>(F);
impl<F> Thunk<F> {
fn new(f: F)
where
F: ContFn,
{
todo!();
}
}
trait ContFn {}
impl<F: FnOnce(Tait) -> ()> ContFn for F {}

View file

@ -1,8 +0,0 @@
include ../tools.mk
OUTPUT_DIR := "$(TMPDIR)/rustdoc"
all:
$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR)
$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs

View file

@ -0,0 +1,16 @@
use run_make_support::{htmldocck, rustdoc, tmp_dir};
fn main() {
let out_dir = tmp_dir().join("rustdoc");
rustdoc()
.input("src/lib.rs")
.crate_name("foobar")
.crate_type("lib")
// This is intentionally using `--output` option flag and not the `output()` method.
.arg("--output")
.arg(&out_dir)
.run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
}

View file

@ -0,0 +1,20 @@
// Ensure keyword docs are present with --document-private-items
//@ compile-flags: --document-private-items
#![feature(rustdoc_internals)]
// @!has "$.index[*][?(@.name=='match')]"
// @has "$.index[*][?(@.name=='foo')]"
// @is "$.index[*][?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]'
// @is "$.index[*][?(@.name=='foo')].docs" '"this is a test!"'
#[doc(keyword = "match")]
/// this is a test!
pub mod foo {}
// @!has "$.index[*][?(@.name=='hello')]"
// @has "$.index[*][?(@.name=='bar')]"
// @is "$.index[*][?(@.name=='bar')].attrs" '["#[doc(keyword = \"hello\")]"]'
// @is "$.index[*][?(@.name=='bar')].docs" '"hello"'
#[doc(keyword = "hello")]
/// hello
mod bar {}

View file

@ -0,0 +1,14 @@
pub fn bad(x: &mut bool) {
if true
*x = true {}
//~^ ERROR cannot multiply `bool` by `&mut bool`
}
pub fn bad2(x: &mut bool) {
let y: bool;
y = true
*x = true;
//~^ ERROR cannot multiply `bool` by `&mut bool`
}
fn main() {}

View file

@ -0,0 +1,29 @@
error[E0369]: cannot multiply `bool` by `&mut bool`
--> $DIR/nested-assignment-may-be-deref.rs:3:5
|
LL | if true
| ---- bool
LL | *x = true {}
| ^- &mut bool
|
help: you might have meant to write a semicolon here
|
LL | if true;
| +
error[E0369]: cannot multiply `bool` by `&mut bool`
--> $DIR/nested-assignment-may-be-deref.rs:10:5
|
LL | y = true
| ---- bool
LL | *x = true;
| ^- &mut bool
|
help: you might have meant to write a semicolon here
|
LL | y = true;
| +
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0369`.

View file

@ -0,0 +1,13 @@
//@ check-pass
#![feature(generic_const_exprs)]
//~^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use
pub fn y<'a, U: 'a>() -> impl IntoIterator<Item = impl IntoIterator<Item = [u8; { 1 + 2 }]> + 'a> {
[[[1, 2, 3]]]
}
// Make sure that the `predicates_of` for `{ 1 + 2 }` don't mention the duplicated lifetimes of
// the *outer* iterator. Whether they should mention the duplicated lifetimes of the *inner*
// iterator are another question, but not really something we need to answer immediately.
fn main() {}

View file

@ -0,0 +1,11 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/double-opaque-parent-predicates.rs:3:12
|
LL | #![feature(generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,21 @@
// Ensure that we properly deal with missing/placeholder types inside GACs.
// issue: rust-lang/rust#124833
#![feature(generic_const_items)]
#![allow(incomplete_features)]
trait Trait {
const K<T>: T;
const Q<'a>: &'a str;
}
impl Trait for () {
const K<T> = ();
//~^ ERROR missing type for `const` item
//~| ERROR mismatched types
//~| ERROR mismatched types
const Q = "";
//~^ ERROR missing type for `const` item
//~| ERROR lifetime parameters or bounds on const `Q` do not match the trait declaration
}
fn main() {}

View file

@ -0,0 +1,48 @@
error[E0308]: mismatched types
--> $DIR/assoc-const-missing-type.rs:12:18
|
LL | const K<T> = ();
| - ^^ expected type parameter `T`, found `()`
| |
| expected this type parameter
|
= note: expected type parameter `T`
found unit type `()`
error: missing type for `const` item
--> $DIR/assoc-const-missing-type.rs:12:15
|
LL | const K<T> = ();
| ^ help: provide a type for the associated constant: `()`
error[E0195]: lifetime parameters or bounds on const `Q` do not match the trait declaration
--> $DIR/assoc-const-missing-type.rs:16:12
|
LL | const Q<'a>: &'a str;
| ---- lifetimes in impl do not match this const in trait
...
LL | const Q = "";
| ^ lifetimes do not match const in trait
error: missing type for `const` item
--> $DIR/assoc-const-missing-type.rs:16:12
|
LL | const Q = "";
| ^ help: provide a type for the associated constant: `: &str`
error[E0308]: mismatched types
--> $DIR/assoc-const-missing-type.rs:12:18
|
LL | const K<T> = ();
| - ^^ expected type parameter `T`, found `()`
| |
| expected this type parameter
|
= note: expected type parameter `T`
found unit type `()`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0195, E0308.
For more information about an error, try `rustc --explain E0195`.

View file

@ -0,0 +1,59 @@
//! This test checks that we allow subtyping predicates that contain opaque types.
//! No hidden types are being constrained in the subtyping predicate, but type and
//! lifetime variables get subtyped in the generic parameter list of the opaque.
use std::iter;
mod either {
pub enum Either<L, R> {
Left(L),
Right(R),
}
impl<L: Iterator, R: Iterator<Item = L::Item>> Iterator for Either<L, R> {
type Item = L::Item;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
pub use self::Either::{Left, Right};
}
pub enum BabeConsensusLogRef<'a> {
NextEpochData(BabeNextEpochRef<'a>),
NextConfigData,
}
impl<'a> BabeConsensusLogRef<'a> {
pub fn scale_encoding(
&self,
) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
//~^ ERROR is not satisfied
//~| ERROR is not satisfied
//~| ERROR is not satisfied
match self {
BabeConsensusLogRef::NextEpochData(digest) => either::Left(either::Left(
digest.scale_encoding().map(either::Left).map(either::Left),
)),
BabeConsensusLogRef::NextConfigData => either::Right(
// The Opaque type from ``scale_encoding` gets used opaquely here, while the `R`
// generic parameter of `Either` contains type variables that get subtyped and the
// opaque type contains lifetime variables that get subtyped.
iter::once(either::Right(either::Left([1])))
.chain(std::iter::once([1]).map(either::Right).map(either::Right)),
),
}
}
}
pub struct BabeNextEpochRef<'a>(&'a ());
impl<'a> BabeNextEpochRef<'a> {
pub fn scale_encoding(
&self,
) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
std::iter::once([1])
}
}
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0277]: the trait bound `Either<Either<Map<Map<impl Iterator<Item = impl AsRef<[u8]> + Clone + '_> + Clone + '_, fn(impl AsRef<[u8]> + Clone + '_) -> Either<impl AsRef<[u8]> + Clone + '_, _> {Either::<impl AsRef<[u8]> + Clone + '_, _>::Left}>, fn(Either<impl AsRef<[u8]> + Clone + '_, _>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Left}>, _>, std::iter::Chain<std::iter::Once<Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>>, Map<Map<std::iter::Once<[{integer}; 1]>, fn([{integer}; 1]) -> Either<[{integer}; 1], [{integer}; 1]> {Either::<[{integer}; 1], [{integer}; 1]>::Right}>, fn(Either<[{integer}; 1], [{integer}; 1]>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Right}>>>: Clone` is not satisfied
--> $DIR/lazy_subtyping_of_opaques.rs:30:10
|
LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Either<Either<Map<Map<impl Iterator<Item = impl AsRef<[u8]> + Clone + '_> + Clone + '_, fn(impl AsRef<[u8]> + Clone + '_) -> Either<impl AsRef<[u8]> + Clone + '_, _> {Either::<impl AsRef<[u8]> + Clone + '_, _>::Left}>, fn(Either<impl AsRef<[u8]> + Clone + '_, _>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Left}>, _>, std::iter::Chain<std::iter::Once<Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>>, Map<Map<std::iter::Once<[{integer}; 1]>, fn([{integer}; 1]) -> Either<[{integer}; 1], [{integer}; 1]> {Either::<[{integer}; 1], [{integer}; 1]>::Right}>, fn(Either<[{integer}; 1], [{integer}; 1]>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Right}>>>`
error[E0277]: the trait bound `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>: AsRef<[u8]>` is not satisfied
--> $DIR/lazy_subtyping_of_opaques.rs:30:31
|
LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsRef<[u8]>` is not implemented for `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>`
error[E0277]: the trait bound `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>: Clone` is not satisfied
--> $DIR/lazy_subtyping_of_opaques.rs:30:31
|
LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,7 +1,12 @@
struct A<B>(B); struct A<B>(B);
impl<B>A<B>{fn d(){fn d(){Self(1)}}}
//~^ ERROR the size for values of type `B` cannot be known at compilation time impl<B> A<B> {
//~| ERROR the size for values of type `B` cannot be known at compilation time fn d() {
//~| ERROR mismatched types fn d() {
//~| ERROR mismatched types Self(1)
//~| ERROR `main` function not found in crate //~^ ERROR can't reference `Self` constructor from outer item
}
}
}
fn main() {}

View file

@ -1,79 +1,12 @@
error[E0601]: `main` function not found in crate `do_not_ice_on_note_and_explain` error[E0401]: can't reference `Self` constructor from outer item
--> $DIR/do-not-ice-on-note_and_explain.rs:2:37 --> $DIR/do-not-ice-on-note_and_explain.rs:6:13
| |
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}} LL | impl<B> A<B> {
| ^ consider adding a `main` function to `$DIR/do-not-ice-on-note_and_explain.rs` | ------------ the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
...
LL | Self(1)
| ^^^^ help: replace `Self` with the actual type: `A`
error[E0277]: the size for values of type `B` cannot be known at compilation time error: aborting due to 1 previous error
--> $DIR/do-not-ice-on-note_and_explain.rs:2:32
|
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
| - ---- ^ doesn't have a size known at compile-time
| | |
| | required by a bound introduced by this call
| this type parameter needs to be `Sized`
|
note: required by a bound in `A`
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
|
LL | struct A<B>(B);
| ^ required by this bound in `A`
error[E0308]: mismatched types For more information about this error, try `rustc --explain E0401`.
--> $DIR/do-not-ice-on-note_and_explain.rs:2:32
|
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
| ---- ^ expected type parameter `B`, found integer
| |
| arguments to this function are incorrect
|
= note: expected type parameter `B`
found type `{integer}`
note: tuple struct defined here
--> $DIR/do-not-ice-on-note_and_explain.rs:1:8
|
LL | struct A<B>(B);
| ^
error[E0308]: mismatched types
--> $DIR/do-not-ice-on-note_and_explain.rs:2:27
|
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
| ^^^^^^^ expected `()`, found `A<B>`
|
= note: expected unit type `()`
found struct `A<B>`
help: consider using a semicolon here
|
LL | impl<B>A<B>{fn d(){fn d(){Self(1);}}}
| +
help: try adding a return type
|
LL | impl<B>A<B>{fn d(){fn d() -> A<B>{Self(1)}}}
| +++++++
error[E0277]: the size for values of type `B` cannot be known at compilation time
--> $DIR/do-not-ice-on-note_and_explain.rs:2:27
|
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
| - ^^^^^^^ doesn't have a size known at compile-time
| |
| this type parameter needs to be `Sized`
|
note: required by an implicit `Sized` bound in `A`
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
|
LL | struct A<B>(B);
| ^ required by the implicit `Sized` requirement on this type parameter in `A`
help: you could relax the implicit `Sized` bound on `B` if it were used through indirection like `&B` or `Box<B>`
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
|
LL | struct A<B>(B);
| ^ - ...if indirection were used here: `Box<B>`
| |
| this could be changed to `B: ?Sized`...
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0277, E0308, E0601.
For more information about an error, try `rustc --explain E0277`.

View file

@ -6,8 +6,12 @@ struct S0(usize);
impl S0 { impl S0 {
fn foo() { fn foo() {
const C: S0 = Self(0); const C: S0 = Self(0);
//~^ WARN can't reference `Self` constructor from outer item
//~| WARN this was previously accepted by the compiler but is being phased out
fn bar() -> S0 { fn bar() -> S0 {
Self(0) Self(0)
//~^ WARN can't reference `Self` constructor from outer item
//~| WARN this was previously accepted by the compiler but is being phased out
} }
} }
} }

View file

@ -0,0 +1,27 @@
warning: can't reference `Self` constructor from outer item
--> $DIR/self-ctor-nongeneric.rs:8:23
|
LL | impl S0 {
| ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
LL | fn foo() {
LL | const C: S0 = Self(0);
| ^^^^ help: replace `Self` with the actual type: `S0`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #124186 <https://github.com/rust-lang/rust/issues/124186>
= note: `#[warn(self_constructor_from_outer_item)]` on by default
warning: can't reference `Self` constructor from outer item
--> $DIR/self-ctor-nongeneric.rs:12:13
|
LL | impl S0 {
| ------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
...
LL | Self(0)
| ^^^^ help: replace `Self` with the actual type: `S0`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #124186 <https://github.com/rust-lang/rust/issues/124186>
warning: 2 warnings emitted

View file

@ -0,0 +1,14 @@
struct S0<T>(T);
impl<T> S0<T> {
fn foo() {
const C: S0<i32> = Self(0);
//~^ ERROR can't reference `Self` constructor from outer item
fn bar() -> S0<i32> {
Self(0)
//~^ ERROR can't reference `Self` constructor from outer item
}
}
}
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0401]: can't reference `Self` constructor from outer item
--> $DIR/self-ctor.rs:5:28
|
LL | impl<T> S0<T> {
| ------------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
LL | fn foo() {
LL | const C: S0<i32> = Self(0);
| ^^^^ help: replace `Self` with the actual type: `S0`
error[E0401]: can't reference `Self` constructor from outer item
--> $DIR/self-ctor.rs:8:13
|
LL | impl<T> S0<T> {
| ------------- the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference
...
LL | Self(0)
| ^^^^ help: replace `Self` with the actual type: `S0`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0401`.

View file

@ -0,0 +1,30 @@
#![feature(type_alias_impl_trait)]
//! This test used to ICE rust-lang/rust#124891
//! because we added an assertion for catching cases where opaque types get
//! registered during the processing of subtyping predicates.
type Tait = impl FnOnce() -> ();
fn reify_as_tait() -> Thunk<Tait> {
Thunk::new(|cont| cont)
//~^ ERROR: mismatched types
//~| ERROR: mismatched types
}
struct Thunk<F>(F);
impl<F> Thunk<F> {
fn new(f: F)
where
F: ContFn,
{
todo!();
}
}
trait ContFn {}
impl<F: FnOnce(Tait) -> ()> ContFn for F {}
fn main() {}

View file

@ -0,0 +1,26 @@
error[E0308]: mismatched types
--> $DIR/lazy_subtyping_of_opaques.rs:10:23
|
LL | type Tait = impl FnOnce() -> ();
| ------------------- the found opaque type
...
LL | Thunk::new(|cont| cont)
| ^^^^ expected `()`, found opaque type
|
= note: expected unit type `()`
found opaque type `Tait`
error[E0308]: mismatched types
--> $DIR/lazy_subtyping_of_opaques.rs:10:5
|
LL | fn reify_as_tait() -> Thunk<Tait> {
| ----------- expected `Thunk<_>` because of return type
LL | Thunk::new(|cont| cont)
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `Thunk<_>`, found `()`
|
= note: expected struct `Thunk<_>`
found unit type `()`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -389,8 +389,11 @@ exclude_labels = [
[autolabel."WG-trait-system-refactor"] [autolabel."WG-trait-system-refactor"]
trigger_files = [ trigger_files = [
"compiler/rustc_middle/src/traits/solve",
"compiler/rustc_next_trait_solver",
"compiler/rustc_trait_selection/src/solve", "compiler/rustc_trait_selection/src/solve",
"compiler/rustc_middle/src/traits/solve" "compiler/rustc_type_ir/src/solve",
"tests/ui/traits/next-solver",
] ]
[autolabel."PG-exploit-mitigations"] [autolabel."PG-exploit-mitigations"]