Merge from rustc

This commit is contained in:
Ralf Jung 2023-06-17 17:42:18 +02:00
commit 14155e95b1
166 changed files with 1875 additions and 1960 deletions

View file

@ -38,6 +38,7 @@ jobs:
env:
CI_JOB_NAME: "${{ matrix.name }}"
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}"
SCCACHE_BUCKET: rust-lang-ci-sccache2
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
CACHE_DOMAIN: ci-caches.rust-lang.org
@ -143,6 +144,17 @@ jobs:
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
if: success() && !env.SKIP_JOB
- name: create github artifacts
run: src/ci/scripts/create-doc-artifacts.sh
if: success() && !env.SKIP_JOB
- name: upload artifacts to github
uses: actions/upload-artifact@v3
with:
name: "${{ env.DOC_ARTIFACT_NAME }}"
path: obj/artifacts/doc
if-no-files-found: ignore
retention-days: 5
if: success() && !env.SKIP_JOB
- name: upload artifacts to S3
run: src/ci/scripts/upload-artifacts.sh
env:
@ -156,6 +168,7 @@ jobs:
env:
CI_JOB_NAME: "${{ matrix.name }}"
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}"
SCCACHE_BUCKET: rust-lang-ci-sccache2
DEPLOY_BUCKET: rust-lang-ci2
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
@ -557,6 +570,17 @@ jobs:
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
if: success() && !env.SKIP_JOB
- name: create github artifacts
run: src/ci/scripts/create-doc-artifacts.sh
if: success() && !env.SKIP_JOB
- name: upload artifacts to github
uses: actions/upload-artifact@v3
with:
name: "${{ env.DOC_ARTIFACT_NAME }}"
path: obj/artifacts/doc
if-no-files-found: ignore
retention-days: 5
if: success() && !env.SKIP_JOB
- name: upload artifacts to S3
run: src/ci/scripts/upload-artifacts.sh
env:
@ -571,6 +595,7 @@ jobs:
DIST_TRY_BUILD: 1
CI_JOB_NAME: "${{ matrix.name }}"
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}"
SCCACHE_BUCKET: rust-lang-ci-sccache2
DEPLOY_BUCKET: rust-lang-ci2
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
@ -672,6 +697,17 @@ jobs:
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
if: success() && !env.SKIP_JOB
- name: create github artifacts
run: src/ci/scripts/create-doc-artifacts.sh
if: success() && !env.SKIP_JOB
- name: upload artifacts to github
uses: actions/upload-artifact@v3
with:
name: "${{ env.DOC_ARTIFACT_NAME }}"
path: obj/artifacts/doc
if-no-files-found: ignore
retention-days: 5
if: success() && !env.SKIP_JOB
- name: upload artifacts to S3
run: src/ci/scripts/upload-artifacts.sh
env:

View file

@ -108,6 +108,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
self.const_uint(self.type_u64(), i)
}
fn const_u128(&self, i: u128) -> RValue<'gcc> {
self.const_uint_big(self.type_u128(), i)
}
fn const_usize(&self, i: u64) -> RValue<'gcc> {
let bit_size = self.data_layout().pointer_size.bits();
if bit_size < 64 {
@ -254,7 +258,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
// SIMD builtins require a constant value.
self.bitcast_if_needed(value, typ)
}
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None)
}

View file

@ -168,6 +168,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
self.const_uint(self.type_i64(), i)
}
fn const_u128(&self, i: u128) -> &'ll Value {
self.const_uint_big(self.type_i128(), i)
}
fn const_usize(&self, i: u64) -> &'ll Value {
let bit_size = self.data_layout().pointer_size.bits();
if bit_size < 64 {

View file

@ -429,7 +429,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
return existing_di_node;
}
debug!("type_di_node: {:?}", t);
debug!("type_di_node: {:?} kind: {:?}", t, t.kind());
let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {

View file

@ -412,13 +412,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
enum_type_and_layout.size.bits(),
enum_type_and_layout.align.abi.bits() as u32,
Size::ZERO.bits(),
discr_value.opt_single_val().map(|value| {
// NOTE(eddyb) do *NOT* remove this assert, until
// we pass the full 128-bit value to LLVM, otherwise
// truncation will be silent and remain undetected.
assert_eq!(value as u64 as u128, value);
cx.const_u64(value as u64)
}),
discr_value.opt_single_val().map(|value| cx.const_u128(value)),
DIFlags::FlagZero,
variant_member_info.variant_struct_type_di_node,
)

View file

@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{ErrorGuaranteed, Handler};
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_metadata::find_native_static_library;
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
@ -2682,6 +2682,30 @@ fn add_upstream_native_libraries(
}
}
// Rehome lib paths (which exclude the library file name) that point into the sysroot lib directory
// to be relative to the sysroot directory, which may be a relative path specified by the user.
//
// If the sysroot is a relative path, and the sysroot libs are specified as an absolute path, the
// linker command line can be non-deterministic due to the paths including the current working
// directory. The linker command line needs to be deterministic since it appears inside the PDB
// file generated by the MSVC linker. See https://github.com/rust-lang/rust/issues/112586.
//
// The returned path will always have `fix_windows_verbatim_for_gcc()` applied to it.
fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf {
let sysroot_lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
let canonical_sysroot_lib_path =
{ try_canonicalize(&sysroot_lib_path).unwrap_or_else(|_| sysroot_lib_path.clone()) };
let canonical_lib_dir = try_canonicalize(lib_dir).unwrap_or_else(|_| lib_dir.to_path_buf());
if canonical_lib_dir == canonical_sysroot_lib_path {
// This path, returned by `target_filesearch().get_lib_path()`, has
// already had `fix_windows_verbatim_for_gcc()` applied if needed.
sysroot_lib_path
} else {
fix_windows_verbatim_for_gcc(&lib_dir)
}
}
// Adds the static "rlib" versions of all crates to the command line.
// There's a bit of magic which happens here specifically related to LTO,
// namely that we remove upstream object files.
@ -2713,7 +2737,13 @@ fn add_static_crate<'a>(
let cratepath = &src.rlib.as_ref().unwrap().0;
let mut link_upstream = |path: &Path| {
cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
let rlib_path = if let Some(dir) = path.parent() {
let file_name = path.file_name().expect("rlib path has no file name path component");
rehome_sysroot_lib_dir(sess, &dir).join(file_name)
} else {
fix_windows_verbatim_for_gcc(path)
};
cmd.link_rlib(&rlib_path);
};
if !are_upstream_rust_objects_already_included(sess)
@ -2782,7 +2812,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
// what its name is
let parent = cratepath.parent();
if let Some(dir) = parent {
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
cmd.include_path(&rehome_sysroot_lib_dir(sess, dir));
}
let stem = cratepath.file_stem().unwrap().to_str().unwrap();
// Convert library file-stem into a cc -l argument.

View file

@ -15,6 +15,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
fn const_i32(&self, i: i32) -> Self::Value;
fn const_u32(&self, i: u32) -> Self::Value;
fn const_u64(&self, i: u64) -> Self::Value;
fn const_u128(&self, i: u128) -> Self::Value;
fn const_usize(&self, i: u64) -> Self::Value;
fn const_u8(&self, i: u8) -> Self::Value;
fn const_real(&self, t: Self::Type, val: f64) -> Self::Value;

View file

@ -781,8 +781,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
);
return;
}
Ok(Some(ImplSource::Closure(data))) => {
if !tcx.is_const_fn_raw(data.closure_def_id) {
// Closure: Fn{Once|Mut}
Ok(Some(ImplSource::Builtin(_)))
if poly_trait_pred.self_ty().skip_binder().is_closure()
&& tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
{
let ty::Closure(closure_def_id, substs) =
*poly_trait_pred.self_ty().no_bound_vars().unwrap().kind()
else {
unreachable!()
};
if !tcx.is_const_fn_raw(closure_def_id) {
self.check_op(ops::FnCallNonConst {
caller,
callee,

View file

@ -172,7 +172,7 @@ impl Qualif for NeedsNonConstDrop {
if !matches!(
impl_src,
ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
) {
// If our const destruct candidate is not ConstDestruct or implied by the param env,
// then it's bad

View file

@ -63,6 +63,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"),
ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"),
ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"),

View file

@ -9,7 +9,7 @@ use rustc_session::parse::{feature_err, ParseSess};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::edition::Edition;
use rustc_span::{Span, SyntaxContext};
use rustc_span::Span;
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
@ -72,7 +72,7 @@ pub(super) fn parse(
// `SyntaxContext::root()` from a foreign crate will
// have the edition of that crate (which we manually
// retrieve via the `edition` parameter).
if span.ctxt() == SyntaxContext::root() {
if span.ctxt().is_root() {
edition
} else {
span.edition()

View file

@ -260,6 +260,8 @@ language_item_table! {
EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None;
OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
// Experimental language item for Miri
PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1);
PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1);

View file

@ -0,0 +1,124 @@
use rustc_ast::TraitObjectSyntax;
use rustc_errors::{Diagnostic, StashKey};
use rustc_hir as hir;
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use super::AstConv;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Make sure that we are in the condition to suggest the blanket implementation.
pub(super) fn maybe_lint_blanket_trait_impl(
&self,
self_ty: &hir::Ty<'_>,
diag: &mut Diagnostic,
) {
let tcx = self.tcx();
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
}),
..
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
{
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {}: {}", param_name, impl_trait_name))
} else {
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
};
diag.multipart_suggestion(
format!("alternatively use a blanket \
implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"),
vec![
(self_ty.span, param_name),
add_generic_sugg,
],
Applicability::MaybeIncorrect,
);
}
}
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
let tcx = self.tcx();
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
self_ty.kind
{
let needs_bracket = in_path
&& !tcx
.sess
.source_map()
.span_to_prev_source(self_ty.span)
.ok()
.is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
let mut sugg = Vec::from_iter([(
self_ty.span.shrink_to_lo(),
format!(
"{}dyn {}",
if needs_bracket { "<" } else { "" },
if is_global { "(" } else { "" },
),
)]);
if is_global || needs_bracket {
sugg.push((
self_ty.span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
));
}
if self_ty.span.edition().rust_2021() {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
if self_ty.span.can_be_used_for_suggestions() {
diag.multipart_suggestion_verbose(
label,
sugg,
Applicability::MachineApplicable,
);
}
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
} else {
let msg = "trait objects without an explicit `dyn` are deprecated";
tcx.struct_span_lint_hir(
BARE_TRAIT_OBJECTS,
self_ty.hir_id,
self_ty.span,
msg,
|lint| {
lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
lint
},
);
}
}
}
}

View file

@ -4,6 +4,7 @@
mod errors;
pub mod generics;
mod lint;
use crate::astconv::errors::prohibit_assoc_ty_binding;
use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args};
@ -19,7 +20,7 @@ use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
MultiSpan, StashKey,
MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@ -33,14 +34,12 @@ use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{DynKind, ToPredicate};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::error_reporting::{
report_object_safety_error, suggestions::NextTypeParamName,
};
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{
self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt,
@ -1458,7 +1457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
self.tcx().at(span).type_of(did).subst(self.tcx(), substs)
let ty = self.tcx().at(span).type_of(did);
if matches!(self.tcx().def_kind(did), DefKind::TyAlias)
&& ty.skip_binder().has_opaque_types()
{
// Type aliases referring to types that contain opaque types (but aren't just directly
// referencing a single opaque type) get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
let alias_ty = self.tcx().mk_alias_ty(did, substs);
self.tcx().mk_alias(ty::Weak, alias_ty)
} else {
ty.subst(self.tcx(), substs)
}
}
fn conv_object_ty_poly_trait_ref(
@ -3703,115 +3714,4 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Some(r)
}
/// Make sure that we are in the condition to suggest the blanket implementation.
fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
let tcx = self.tcx();
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
}),
..
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
{
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {}: {}", param_name, impl_trait_name))
} else {
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
};
diag.multipart_suggestion(
format!("alternatively use a blanket \
implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"),
vec![
(self_ty.span, param_name),
add_generic_sugg,
],
Applicability::MaybeIncorrect,
);
}
}
fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
let tcx = self.tcx();
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
self_ty.kind
{
let needs_bracket = in_path
&& !tcx
.sess
.source_map()
.span_to_prev_source(self_ty.span)
.ok()
.is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
let mut sugg = Vec::from_iter([(
self_ty.span.shrink_to_lo(),
format!(
"{}dyn {}",
if needs_bracket { "<" } else { "" },
if is_global { "(" } else { "" },
),
)]);
if is_global || needs_bracket {
sugg.push((
self_ty.span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
));
}
if self_ty.span.edition().rust_2021() {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
if self_ty.span.can_be_used_for_suggestions() {
diag.multipart_suggestion_verbose(
label,
sugg,
Applicability::MachineApplicable,
);
}
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
} else {
let msg = "trait objects without an explicit `dyn` are deprecated";
tcx.struct_span_lint_hir(
BARE_TRAIT_OBJECTS,
self_ty.hir_id,
self_ty.span,
msg,
|lint| {
lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
lint
},
);
}
}
}
}

View file

@ -217,10 +217,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl);
}
hir::ItemKind::Static(ty, ..) => {
check_item_type(tcx, def_id, ty.span, false);
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
}
hir::ItemKind::Const(ty, ..) => {
check_item_type(tcx, def_id, ty.span, false);
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
}
hir::ItemKind::Struct(_, ast_generics) => {
check_type_defn(tcx, item, false);
@ -242,6 +242,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
// `ForeignItem`s are handled separately.
hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::TyAlias(hir_ty, ..) => {
if tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
// Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
}
}
_ => {}
}
}
@ -258,7 +264,9 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
hir::ForeignItemKind::Fn(decl, ..) => {
check_item_fn(tcx, def_id, item.ident, item.span, decl)
}
hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true),
hir::ForeignItemKind::Static(ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
}
hir::ForeignItemKind::Type => (),
}
}
@ -1100,20 +1108,32 @@ fn check_item_fn(
})
}
fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) {
enum UnsizedHandling {
Forbid,
Allow,
AllowIfForeignTail,
}
fn check_item_type(
tcx: TyCtxt<'_>,
item_id: LocalDefId,
ty_span: Span,
unsized_handling: UnsizedHandling,
) {
debug!("check_item_type: {:?}", item_id);
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
let ty = tcx.type_of(item_id).subst_identity();
let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
let mut forbid_unsized = true;
if allow_foreign_ty {
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
if let ty::Foreign(_) = tail.kind() {
forbid_unsized = false;
let forbid_unsized = match unsized_handling {
UnsizedHandling::Forbid => true,
UnsizedHandling::Allow => false,
UnsizedHandling::AllowIfForeignTail => {
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
!matches!(tail.kind(), ty::Foreign(_))
}
}
};
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
if forbid_unsized {

View file

@ -200,35 +200,32 @@ fn do_orphan_check_impl<'tcx>(
NonlocalImpl::DisallowOther,
),
// trait Id { type This: ?Sized; }
// impl<T: ?Sized> Id for T {
// type This = T;
// }
// impl<T: ?Sized> AutoTrait for <T as Id>::This {}
ty::Alias(AliasKind::Projection, _) => (
LocalImpl::Disallow { problematic_kind: "associated type" },
NonlocalImpl::DisallowOther,
),
// ```
// struct S<T>(T);
// impl<T: ?Sized> S<T> {
// type This = T;
// }
// impl<T: ?Sized> AutoTrait for S<T>::This {}
// ```
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
ty::Alias(AliasKind::Inherent, _) => (
LocalImpl::Disallow { problematic_kind: "associated type" },
NonlocalImpl::DisallowOther,
),
// type Opaque = impl Trait;
// impl AutoTrait for Opaque {}
ty::Alias(AliasKind::Opaque, _) => (
LocalImpl::Disallow { problematic_kind: "opaque type" },
NonlocalImpl::DisallowOther,
),
ty::Alias(kind, _) => {
let problematic_kind = match kind {
// trait Id { type This: ?Sized; }
// impl<T: ?Sized> Id for T {
// type This = T;
// }
// impl<T: ?Sized> AutoTrait for <T as Id>::This {}
AliasKind::Projection => "associated type",
// type Foo = (impl Sized, bool)
// impl AutoTrait for Foo {}
AliasKind::Weak => "type alias",
// type Opaque = impl Trait;
// impl AutoTrait for Opaque {}
AliasKind::Opaque => "opaque type",
// ```
// struct S<T>(T);
// impl<T: ?Sized> S<T> {
// type This = T;
// }
// impl<T: ?Sized> AutoTrait for S<T>::This {}
// ```
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
AliasKind::Inherent => "associated type",
};
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
}
ty::Bool
| ty::Char

View file

@ -122,6 +122,7 @@ pub(super) fn explicit_item_bounds(
};
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
_ => bug!("item_bounds called on {:?}", def_id),
};
ty::EarlyBinder::bind(bounds)

View file

@ -128,7 +128,9 @@ fn diagnostic_hir_wf_check<'tcx>(
ref item => bug!("Unexpected TraitItem {:?}", item),
},
hir::Node::Item(item) => match item.kind {
hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
hir::ItemKind::TyAlias(ty, _)
| hir::ItemKind::Static(ty, _, _)
| hir::ItemKind::Const(ty, _) => vec![ty],
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
Some(t) => t
.path

View file

@ -98,7 +98,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: self.tcx.def_span(expr_def_id),
});
@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
None => self.next_ty_var(TypeVariableOrigin {
None => self.next_root_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,

View file

@ -189,6 +189,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn errors_reported_since_creation(&self) -> bool {
self.tcx.sess.err_count() > self.err_count_on_creation
}
pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT))
}
}
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {

View file

@ -2375,6 +2375,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
format!("the associated type `{}`", p)
}
ty::AliasKind::Weak => format!("the type alias `{}`", p),
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
},
};

View file

@ -1465,8 +1465,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
return
};
if let hir::TyKind::OpaqueDef(..) = ty.kind {
// Bounds are respected for `type X = impl Trait`
if cx.tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
// Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
return;
}
if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {

View file

@ -1255,7 +1255,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
ty::Param(..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
| ty::Infer(..)
| ty::Bound(..)
| ty::Error(_)

View file

@ -82,15 +82,40 @@ impl CanonicalVarValues<'_> {
}
pub fn is_identity_modulo_regions(&self) -> bool {
self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
ty::GenericArgKind::Lifetime(_) => true,
ty::GenericArgKind::Type(ty) => {
matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
let mut var = ty::BoundVar::from_u32(0);
for arg in self.var_values {
match arg.unpack() {
ty::GenericArgKind::Lifetime(r) => {
if let ty::ReLateBound(ty::INNERMOST, br) = *r
&& var == br.var
{
var = var + 1;
} else {
// It's ok if this region var isn't unique
}
},
ty::GenericArgKind::Type(ty) => {
if let ty::Bound(ty::INNERMOST, bt) = *ty.kind()
&& var == bt.var
{
var = var + 1;
} else {
return false;
}
}
ty::GenericArgKind::Const(ct) => {
if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind()
&& var == bc
{
var = var + 1;
} else {
return false;
}
}
}
ty::GenericArgKind::Const(ct) => {
matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
}
})
}
true
}
}

View file

@ -3,7 +3,7 @@ use rustc_middle::hir;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::MirSpanview;
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
use rustc_span::{BytePos, Pos, Span};
use std::cmp;
use std::io::{self, Write};
@ -327,7 +327,7 @@ fn compute_block_span(data: &BasicBlockData<'_>, body_span: Span) -> Span {
let mut span = data.terminator().source_info.span;
for statement_span in data.statements.iter().map(|statement| statement.source_info.span) {
// Only combine Spans from the root context, and within the function's body_span.
if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) {
if statement_span.ctxt().is_root() && body_span.contains(statement_span) {
span = span.to(statement_span);
}
}

View file

@ -1903,6 +1903,16 @@ rustc_queries! {
desc { "normalizing `{}`", goal.value.value }
}
/// Do not call this query directly: invoke `normalize` instead.
query normalize_weak_ty(
goal: CanonicalProjectionGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
NoSolution,
> {
desc { "normalizing `{}`", goal.value.value }
}
/// Do not call this query directly: invoke `normalize` instead.
query normalize_inherent_projection_ty(
goal: CanonicalProjectionGoal<'tcx>

View file

@ -448,6 +448,9 @@ pub enum ObligationCauseCode<'tcx> {
/// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy`
ConstParam(Ty<'tcx>),
/// Obligations emitted during the normalization of a weak type alias.
TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId),
}
/// The 'location' at which we try to perform HIR-based wf checking.
@ -643,12 +646,6 @@ pub enum ImplSource<'tcx, N> {
/// ImplSource identifying a particular impl.
UserDefined(ImplSourceUserDefinedData<'tcx, N>),
/// ImplSource for auto trait implementations.
/// This carries the information and nested obligations with regards
/// to an auto implementation for a trait `Trait`. The nested obligations
/// ensure the trait implementation holds for all the constituent types.
AutoImpl(ImplSourceAutoImplData<N>),
/// Successful resolution to an obligation provided by the caller
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
@ -656,84 +653,46 @@ pub enum ImplSource<'tcx, N> {
Param(Vec<N>, ty::BoundConstness),
/// Virtual calls through an object.
Object(ImplSourceObjectData<'tcx, N>),
Object(ImplSourceObjectData<N>),
/// Successful resolution for a builtin trait.
Builtin(ImplSourceBuiltinData<N>),
Builtin(Vec<N>),
/// ImplSource for trait upcasting coercion
TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>),
/// ImplSource automatically generated for a closure. The `DefId` is the ID
/// of the closure expression. This is an `ImplSource::UserDefined` in spirit, but the
/// impl is generated by the compiler and does not appear in the source.
Closure(ImplSourceClosureData<'tcx, N>),
/// Same as above, but for a function pointer type with the given signature.
FnPointer(ImplSourceFnPointerData<'tcx, N>),
/// ImplSource automatically generated for a generator.
Generator(ImplSourceGeneratorData<'tcx, N>),
/// ImplSource automatically generated for a generator backing an async future.
Future(ImplSourceFutureData<'tcx, N>),
TraitUpcasting(ImplSourceTraitUpcastingData<N>),
/// ImplSource for a trait alias.
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
/// ImplSource for a `const Drop` implementation.
ConstDestruct(ImplSourceConstDestructData<N>),
}
impl<'tcx, N> ImplSource<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> {
match self {
ImplSource::UserDefined(i) => i.nested,
ImplSource::Param(n, _) => n,
ImplSource::Builtin(i) => i.nested,
ImplSource::AutoImpl(d) => d.nested,
ImplSource::Closure(c) => c.nested,
ImplSource::Generator(c) => c.nested,
ImplSource::Future(c) => c.nested,
ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
ImplSource::Object(d) => d.nested,
ImplSource::FnPointer(d) => d.nested,
ImplSource::TraitAlias(d) => d.nested,
ImplSource::TraitUpcasting(d) => d.nested,
ImplSource::ConstDestruct(i) => i.nested,
}
}
pub fn borrow_nested_obligations(&self) -> &[N] {
match self {
ImplSource::UserDefined(i) => &i.nested,
ImplSource::Param(n, _) => n,
ImplSource::Builtin(i) => &i.nested,
ImplSource::AutoImpl(d) => &d.nested,
ImplSource::Closure(c) => &c.nested,
ImplSource::Generator(c) => &c.nested,
ImplSource::Future(c) => &c.nested,
ImplSource::Param(n, _) | ImplSource::Builtin(n) => &n,
ImplSource::Object(d) => &d.nested,
ImplSource::FnPointer(d) => &d.nested,
ImplSource::TraitAlias(d) => &d.nested,
ImplSource::TraitUpcasting(d) => &d.nested,
ImplSource::ConstDestruct(i) => &i.nested,
}
}
pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
match self {
ImplSource::UserDefined(i) => &mut i.nested,
ImplSource::Param(n, _) => n,
ImplSource::Builtin(i) => &mut i.nested,
ImplSource::AutoImpl(d) => &mut d.nested,
ImplSource::Closure(c) => &mut c.nested,
ImplSource::Generator(c) => &mut c.nested,
ImplSource::Future(c) => &mut c.nested,
ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
ImplSource::Object(d) => &mut d.nested,
ImplSource::FnPointer(d) => &mut d.nested,
ImplSource::TraitAlias(d) => &mut d.nested,
ImplSource::TraitUpcasting(d) => &mut d.nested,
ImplSource::ConstDestruct(i) => &mut i.nested,
}
}
@ -748,37 +707,12 @@ impl<'tcx, N> ImplSource<'tcx, N> {
nested: i.nested.into_iter().map(f).collect(),
}),
ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData {
nested: i.nested.into_iter().map(f).collect(),
}),
ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()),
ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
upcast_trait_ref: o.upcast_trait_ref,
upcast_trait_def_id: o.upcast_trait_def_id,
vtable_base: o.vtable_base,
nested: o.nested.into_iter().map(f).collect(),
}),
ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData {
trait_def_id: d.trait_def_id,
nested: d.nested.into_iter().map(f).collect(),
}),
ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData {
closure_def_id: c.closure_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData {
generator_def_id: c.generator_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
ImplSource::Future(c) => ImplSource::Future(ImplSourceFutureData {
generator_def_id: c.generator_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData {
fn_ty: p.fn_ty,
nested: p.nested.into_iter().map(f).collect(),
}),
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
alias_def_id: d.alias_def_id,
substs: d.substs,
@ -786,16 +720,10 @@ impl<'tcx, N> ImplSource<'tcx, N> {
}),
ImplSource::TraitUpcasting(d) => {
ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
upcast_trait_ref: d.upcast_trait_ref,
vtable_vptr_slot: d.vtable_vptr_slot,
nested: d.nested.into_iter().map(f).collect(),
})
}
ImplSource::ConstDestruct(i) => {
ImplSource::ConstDestruct(ImplSourceConstDestructData {
nested: i.nested.into_iter().map(f).collect(),
})
}
}
}
}
@ -820,47 +748,7 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceGeneratorData<'tcx, N> {
pub generator_def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// Nested obligations. This can be non-empty if the generator
/// signature contains associated types.
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceFutureData<'tcx, N> {
pub generator_def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// Nested obligations. This can be non-empty if the generator
/// signature contains associated types.
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceClosureData<'tcx, N> {
pub closure_def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// Nested obligations. This can be non-empty if the closure
/// signature contains associated types.
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceAutoImplData<N> {
pub trait_def_id: DefId,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceTraitUpcastingData<'tcx, N> {
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
pub struct ImplSourceTraitUpcastingData<N> {
/// The vtable is formed by concatenating together the method lists of
/// the base object trait and all supertraits, pointers to supertrait vtable will
/// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
@ -870,17 +758,11 @@ pub struct ImplSourceTraitUpcastingData<'tcx, N> {
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceBuiltinData<N> {
pub nested: Vec<N>,
}
#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceObjectData<'tcx, N> {
pub struct ImplSourceObjectData<N> {
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
pub upcast_trait_def_id: DefId,
/// The vtable is formed by concatenating together the method lists of
/// the base object trait and all supertraits, pointers to supertrait vtable will
@ -891,19 +773,6 @@ pub struct ImplSourceObjectData<'tcx, N> {
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceFnPointerData<'tcx, N> {
pub fn_ty: Ty<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceConstDestructData<N> {
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceTraitAliasData<'tcx, N> {

View file

@ -9,15 +9,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
match *self {
super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v),
super::ImplSource::AutoImpl(ref t) => write!(f, "{:?}", t),
super::ImplSource::Closure(ref d) => write!(f, "{:?}", d),
super::ImplSource::Generator(ref d) => write!(f, "{:?}", d),
super::ImplSource::Future(ref d) => write!(f, "{:?}", d),
super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d),
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
@ -25,13 +17,9 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
}
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
}
}
}
@ -46,78 +34,26 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx,
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceGeneratorData<'tcx, N> {
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
self.generator_def_id, self.substs, self.nested
"ImplSourceTraitUpcastingData(vtable_vptr_slot={:?}, nested={:?})",
self.vtable_vptr_slot, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFutureData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceFutureData(generator_def_id={:?}, substs={:?}, nested={:?})",
self.generator_def_id, self.substs, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceClosureData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
self.closure_def_id, self.substs, self.nested
)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ImplSourceBuiltinData(nested={:?})", self.nested)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})",
self.upcast_trait_ref, self.vtable_vptr_slot, self.nested
)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceAutoImplData(trait_def_id={:?}, nested={:?})",
self.trait_def_id, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<'tcx, N> {
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceObjectData(upcast={:?}, vtable_base={}, nested={:?})",
self.upcast_trait_ref, self.vtable_base, self.nested
self.upcast_trait_def_id, self.vtable_base, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFnPointerData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ImplSourceFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
@ -127,9 +63,3 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ImplSourceConstDestructData(nested={:?})", self.nested)
}
}

View file

@ -2012,6 +2012,7 @@ impl<'tcx> TyCtxt<'tcx> {
(ty::Opaque, DefKind::OpaqueTy)
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
| (ty::Weak, DefKind::TyAlias)
);
self.mk_ty_from_kind(Alias(kind, alias_ty))
}

View file

@ -300,6 +300,7 @@ impl<'tcx> Ty<'tcx> {
ty::Placeholder(..) => "higher-ranked type".into(),
ty::Bound(..) => "bound type variable".into(),
ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
ty::Alias(ty::Weak, _) => "type alias".into(),
ty::Param(_) => "type parameter".into(),
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
}

View file

@ -178,7 +178,7 @@ impl FlagComputation {
&ty::Alias(kind, data) => {
self.add_flags(match kind {
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION,
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
});

View file

@ -586,6 +586,24 @@ pub enum Clause<'tcx> {
ConstArgHasType(Const<'tcx>, Ty<'tcx>),
}
impl<'tcx> Binder<'tcx, Clause<'tcx>> {
pub fn as_trait_clause(self) -> Option<Binder<'tcx, TraitPredicate<'tcx>>> {
if let ty::Clause::Trait(trait_clause) = self.skip_binder() {
Some(self.rebind(trait_clause))
} else {
None
}
}
pub fn as_projection_clause(self) -> Option<Binder<'tcx, ProjectionPredicate<'tcx>>> {
if let ty::Clause::Projection(projection_clause) = self.skip_binder() {
Some(self.rebind(projection_clause))
} else {
None
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub enum PredicateKind<'tcx> {
@ -1203,6 +1221,17 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
}
}
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for TraitRef<'tcx> {
#[inline(always)]
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
Binder::dummy(Clause::Trait(TraitPredicate {
trait_ref: self,
constness: ty::BoundConstness::NotConst,
polarity: ty::ImplPolarity::Positive,
}))
}
}
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@ -1211,6 +1240,14 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
}
}
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for Binder<'tcx, TraitRef<'tcx>> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
pred.to_predicate(tcx)
}
}
impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
#[inline(always)]
fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
@ -1240,6 +1277,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
}
}
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyTraitPredicate<'tcx> {
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
self.map_bound(|p| Clause::Trait(p))
}
}
impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx)
@ -1258,6 +1301,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
}
}
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyProjectionPredicate<'tcx> {
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
self.map_bound(|p| Clause::Projection(p))
}
}
impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
PredicateKind::Clause(Clause::Trait(self)).to_predicate(tcx)
@ -1327,6 +1376,23 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
pub fn as_clause(self) -> Option<Binder<'tcx, Clause<'tcx>>> {
let predicate = self.kind();
match predicate.skip_binder() {
PredicateKind::Clause(clause) => Some(predicate.rebind(clause)),
PredicateKind::AliasRelate(..)
| PredicateKind::Subtype(..)
| PredicateKind::Coerce(..)
| PredicateKind::WellFormed(..)
| PredicateKind::ObjectSafe(..)
| PredicateKind::ClosureKind(..)
| PredicateKind::ConstEvaluatable(..)
| PredicateKind::ConstEquate(..)
| PredicateKind::Ambiguous
| PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
}
/// Represents the bounds declared on a particular set of type

View file

@ -731,7 +731,7 @@ pub trait PrettyPrinter<'tcx>:
ty::Foreign(def_id) => {
p!(print_def_path(def_id, &[]));
}
ty::Alias(ty::Projection | ty::Inherent, ref data) => {
ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ref data) => {
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
&& self.tcx().is_impl_trait_in_trait(data.def_id)
{

View file

@ -391,13 +391,13 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> {
/// Relates `a` and `b` structurally, calling the relation for all nested values.
/// Any semantic equality, e.g. of projections, and inference variables have to be
/// handled by the caller.
#[instrument(level = "trace", skip(relation), ret)]
pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
relation: &mut R,
a: Ty<'tcx>,
b: Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let tcx = relation.tcx();
debug!("structurally_relate_tys: a={:?} b={:?}", a, b);
match (a.kind(), b.kind()) {
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
// The caller should handle these cases!

View file

@ -1231,6 +1231,7 @@ impl<'tcx> AliasTy<'tcx> {
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
DefKind::OpaqueTy => ty::Opaque,
DefKind::TyAlias => ty::Weak,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
}
}

View file

@ -15,6 +15,10 @@ pub struct CheckAlignment;
impl<'tcx> MirPass<'tcx> for CheckAlignment {
fn is_enabled(&self, sess: &Session) -> bool {
// FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
if sess.target.llvm_target == "i686-pc-windows-msvc" {
return false;
}
sess.opts.debug_assertions
}

View file

@ -479,11 +479,12 @@ impl<'tcx> Inliner<'tcx> {
// Abort if type validation found anything fishy.
checker.validation?;
// N.B. We still apply our cost threshold to #[inline(always)] functions.
// That attribute is often applied to very large functions that exceed LLVM's (very
// generous) inlining threshold. Such functions are very poor MIR inlining candidates.
// Always inlining #[inline(always)] functions in MIR, on net, slows down the compiler.
let cost = checker.cost;
if let InlineAttr::Always = callee_attrs.inline {
debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost);
Ok(())
} else if cost <= threshold {
if cost <= threshold {
debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold);
Ok(())
} else {

View file

@ -155,15 +155,17 @@ where
// functions and statics defined in the local crate.
let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
place_root_mono_items(cx, mono_items)
let mut placed = place_root_mono_items(cx, mono_items);
for cgu in &mut placed.codegen_units {
cgu.create_size_estimate(tcx);
}
debug_dump(tcx, "ROOTS", &placed.codegen_units, placed.unique_inlined_stats);
placed
};
for cgu in &mut codegen_units {
cgu.create_size_estimate(tcx);
}
debug_dump(tcx, "ROOTS", &codegen_units, unique_inlined_stats);
// Merge until we have at most `max_cgu_count` codegen units.
// `merge_codegen_units` is responsible for updating the CGU size
// estimates.
@ -179,59 +181,34 @@ where
// local functions the definition of which is marked with `#[inline]`.
{
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
place_inlined_mono_items(cx, &mut codegen_units)
};
place_inlined_mono_items(cx, &mut codegen_units);
for cgu in &mut codegen_units {
cgu.create_size_estimate(tcx);
for cgu in &mut codegen_units {
cgu.create_size_estimate(tcx);
}
debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats);
}
debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats);
// Next we try to make as many symbols "internal" as possible, so LLVM has
// more freedom to optimize.
if !tcx.sess.link_dead_code() {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
internalize_symbols(cx, &mut codegen_units, internalization_candidates);
debug_dump(tcx, "INTERNALIZE", &codegen_units, unique_inlined_stats);
}
// Mark one CGU for dead code, if necessary.
let instrument_dead_code =
tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions();
if instrument_dead_code {
assert!(
codegen_units.len() > 0,
"There must be at least one CGU that code coverage data can be generated in."
);
// Find the smallest CGU that has exported symbols and put the dead
// function stubs in that CGU. We look for exported symbols to increase
// the likelihood the linker won't throw away the dead functions.
// FIXME(#92165): In order to truly resolve this, we need to make sure
// the object file (CGU) containing the dead function stubs is included
// in the final binary. This will probably require forcing these
// function symbols to be included via `-u` or `/include` linker args.
let mut cgus: Vec<_> = codegen_units.iter_mut().collect();
cgus.sort_by_key(|cgu| cgu.size_estimate());
let dead_code_cgu =
if let Some(cgu) = cgus.into_iter().rev().find(|cgu| {
cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)
}) {
cgu
} else {
// If there are no CGUs that have externally linked items,
// then we just pick the first CGU as a fallback.
&mut codegen_units[0]
};
dead_code_cgu.make_code_coverage_dead_code_cgu();
mark_code_coverage_dead_code_cgu(&mut codegen_units);
}
// Ensure CGUs are sorted by name, so that we get deterministic results.
assert!(codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str()))));
debug_dump(tcx, "FINAL", &codegen_units, unique_inlined_stats);
codegen_units
}
@ -363,9 +340,7 @@ fn merge_codegen_units<'tcx>(
// Move the mono-items from `smallest` to `second_smallest`
second_smallest.modify_size_estimate(smallest.size_estimate());
for (k, v) in smallest.items_mut().drain() {
second_smallest.items_mut().insert(k, v);
}
second_smallest.items_mut().extend(smallest.items_mut().drain());
// Record that `second_smallest` now contains all the stuff that was
// in `smallest` before.
@ -545,6 +520,28 @@ fn internalize_symbols<'tcx>(
}
}
fn mark_code_coverage_dead_code_cgu<'tcx>(codegen_units: &mut [CodegenUnit<'tcx>]) {
assert!(!codegen_units.is_empty());
// Find the smallest CGU that has exported symbols and put the dead
// function stubs in that CGU. We look for exported symbols to increase
// the likelihood the linker won't throw away the dead functions.
// FIXME(#92165): In order to truly resolve this, we need to make sure
// the object file (CGU) containing the dead function stubs is included
// in the final binary. This will probably require forcing these
// function symbols to be included via `-u` or `/include` linker args.
let dead_code_cgu = codegen_units
.iter_mut()
.filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External))
.min_by_key(|cgu| cgu.size_estimate());
// If there are no CGUs that have externally linked items, then we just
// pick the first CGU as a fallback.
let dead_code_cgu = if let Some(cgu) = dead_code_cgu { cgu } else { &mut codegen_units[0] };
dead_code_cgu.make_code_coverage_dead_code_cgu();
}
fn characteristic_def_id_of_mono_item<'tcx>(
tcx: TyCtxt<'tcx>,
mono_item: MonoItem<'tcx>,

View file

@ -2029,17 +2029,14 @@ impl<'a> Parser<'a> {
let recovered = self.recover_after_dot();
let token = recovered.as_ref().unwrap_or(&self.token);
match token::Lit::from_token(token) {
Some(token_lit) => {
match MetaItemLit::from_token_lit(token_lit, token.span) {
Some(lit) => {
match MetaItemLit::from_token_lit(lit, token.span) {
Ok(lit) => {
self.bump();
Some(lit)
}
Err(err) => {
let span = token.span;
let token::Literal(lit) = token.kind else {
unreachable!();
};
let span = token.uninterpolated_span();
self.bump();
report_lit_error(&self.sess, err, lit, span);
// Pack possible quotes and prefixes from the original literal into

View file

@ -242,6 +242,9 @@ where
}
}
}
ty::Alias(ty::Weak, alias) => {
self.def_id_visitor.visit_def_id(alias.def_id, "type alias", &ty);
}
ty::Alias(ty::Projection, proj) => {
if self.def_id_visitor.skip_assoc_tys() {
// Visitors searching for minimal visibility/reachability want to

View file

@ -507,7 +507,7 @@ impl HygieneData {
self.normalize_to_macro_rules(call_site_ctxt)
};
if call_site_ctxt == SyntaxContext::root() {
if call_site_ctxt.is_root() {
return self.apply_mark_internal(ctxt, expn_id, transparency);
}
@ -671,12 +671,17 @@ impl SyntaxContext {
}
#[inline]
pub(crate) fn as_u32(self) -> u32 {
pub const fn is_root(self) -> bool {
self.0 == SyntaxContext::root().as_u32()
}
#[inline]
pub(crate) const fn as_u32(self) -> u32 {
self.0
}
#[inline]
pub(crate) fn from_u32(raw: u32) -> SyntaxContext {
pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
SyntaxContext(raw)
}
@ -1500,7 +1505,7 @@ impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
const TAG_EXPANSION: u8 = 0;
const TAG_NO_EXPANSION: u8 = 1;
if *self == SyntaxContext::root() {
if self.is_root() {
TAG_NO_EXPANSION.hash_stable(ctx, hasher);
} else {
TAG_EXPANSION.hash_stable(ctx, hasher);

View file

@ -826,9 +826,9 @@ impl Span {
// Return the macro span on its own to avoid weird diagnostic output. It is preferable to
// have an incomplete span than a completely nonsensical one.
if span_data.ctxt != end_data.ctxt {
if span_data.ctxt == SyntaxContext::root() {
if span_data.ctxt.is_root() {
return end;
} else if end_data.ctxt == SyntaxContext::root() {
} else if end_data.ctxt.is_root() {
return self;
}
// Both spans fall within a macro.
@ -837,7 +837,7 @@ impl Span {
Span::new(
cmp::min(span_data.lo, end_data.lo),
cmp::max(span_data.hi, end_data.hi),
if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
if span_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt },
if span_data.parent == end_data.parent { span_data.parent } else { None },
)
}
@ -855,7 +855,7 @@ impl Span {
Span::new(
span.hi,
end.lo,
if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
if end.ctxt.is_root() { end.ctxt } else { span.ctxt },
if span.parent == end.parent { span.parent } else { None },
)
}
@ -879,9 +879,9 @@ impl Span {
// Return the macro span on its own to avoid weird diagnostic output. It is preferable to
// have an incomplete span than a completely nonsensical one.
if span_data.ctxt != end_data.ctxt {
if span_data.ctxt == SyntaxContext::root() {
if span_data.ctxt.is_root() {
return end;
} else if end_data.ctxt == SyntaxContext::root() {
} else if end_data.ctxt.is_root() {
return self;
}
// Both spans fall within a macro.
@ -890,7 +890,7 @@ impl Span {
Span::new(
span_data.lo,
end_data.lo,
if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
if end_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt },
if span_data.parent == end_data.parent { span_data.parent } else { None },
)
}

View file

@ -1156,6 +1156,7 @@ symbols! {
ptr_null_mut,
ptr_offset_from,
ptr_offset_from_unsigned,
ptr_unique,
pub_macro_rules,
pub_restricted,
public,

View file

@ -483,6 +483,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
}
ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"),
ty::Alias(ty::Weak, _) => bug!("symbol_names: unexpected weak projection"),
ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"),
ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"),
}

View file

@ -105,7 +105,7 @@ pub(super) trait GoalKind<'tcx>:
fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx>;
@ -115,7 +115,7 @@ pub(super) trait GoalKind<'tcx>:
fn consider_implied_clause(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
) -> QueryResult<'tcx> {
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
@ -131,7 +131,7 @@ pub(super) trait GoalKind<'tcx>:
fn consider_alias_bound_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
) -> QueryResult<'tcx> {
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
ecx.validate_alias_bound_self_from_param_env(goal)
@ -144,7 +144,7 @@ pub(super) trait GoalKind<'tcx>:
fn consider_object_bound_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
) -> QueryResult<'tcx> {
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
let tcx = ecx.tcx();
@ -467,11 +467,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
candidates: &mut Vec<Candidate<'tcx>>,
) {
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
match G::consider_implied_clause(self, goal, assumption, []) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
if let Some(clause) = assumption.as_clause() {
match G::consider_implied_clause(self, goal, clause, []) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
}
Err(NoSolution) => (),
}
Err(NoSolution) => (),
}
}
}
@ -508,20 +510,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Placeholder(..)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Alias(ty::Inherent, _)
| ty::Alias(ty::Weak, _)
| ty::Error(_) => return,
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty,
};
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
{
match G::consider_alias_bound_candidate(self, goal, assumption) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
if let Some(clause) = assumption.as_clause() {
match G::consider_alias_bound_candidate(self, goal, clause) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
}
Err(NoSolution) => (),
}
Err(NoSolution) => (),
}
}
}
@ -675,18 +680,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// projection predicates that we reach by elaborating the principal trait ref,
// since that'll cause ambiguity.
//
// We can remove this when we have implemented intersections in responses.
// We can remove this when we have implemented lifetime intersections in responses.
if assumption.to_opt_poly_projection_pred().is_some()
&& !own_bounds.contains(&assumption)
{
continue;
}
match G::consider_object_bound_candidate(self, goal, assumption) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
if let Some(clause) = assumption.as_clause() {
match G::consider_object_bound_candidate(self, goal, clause) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
}
Err(NoSolution) => (),
}
Err(NoSolution) => (),
}
}
}

View file

@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Infer(_) => {

View file

@ -208,8 +208,25 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
t
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let r = self.infcx.shallow_resolve(r);
fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match self.canonicalize_mode {
CanonicalizeMode::Input => {
// Don't resolve infer vars in input, since it affects
// caching and may cause trait selection bugs which rely
// on regions to be equal.
}
CanonicalizeMode::Response { .. } => {
if let ty::ReVar(vid) = *r {
r = self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.infcx.tcx, vid);
}
}
}
let kind = match *r {
ty::ReLateBound(..) => return r,

View file

@ -263,7 +263,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
let new_canonical_response =
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
if !new_canonical_response.value.var_values.is_identity() {
// We only check for modulo regions as we convert all regions in
// the input to new existentials, even if they're expected to be
// `'static` or a placeholder region.
if !new_canonical_response.value.var_values.is_identity_modulo_regions() {
bug!(
"unstable result: re-canonicalized goal={canonical_goal:#?} \
first_response={canonical_response:#?} \

View file

@ -29,6 +29,7 @@ mod opaques;
mod project_goals;
mod search_graph;
mod trait_goals;
mod weak_types;
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
pub use fulfill::FulfillmentCtxt;

View file

@ -57,6 +57,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
DefKind::AnonConst => self.normalize_anon_const(goal),
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
DefKind::TyAlias => self.normalize_weak_type(goal),
kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
}
}
@ -105,15 +106,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
if let Some(projection_pred) = assumption.as_projection_clause()
&& projection_pred.projection_def_id() == goal.predicate.def_id()
{
ecx.probe(|ecx| {
let assumption_projection_pred =
ecx.instantiate_binder_with_infer(poly_projection_pred);
ecx.instantiate_binder_with_infer(projection_pred);
ecx.eq(
goal.param_env,
goal.predicate.projection_ty,

View file

@ -81,17 +81,17 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
&& poly_trait_pred.def_id() == goal.predicate.def_id()
&& poly_trait_pred.polarity() == goal.predicate.polarity
if let Some(trait_clause) = assumption.as_trait_clause()
&& trait_clause.def_id() == goal.predicate.def_id()
&& trait_clause.polarity() == goal.predicate.polarity
{
// FIXME: Constness
ecx.probe(|ecx| {
let assumption_trait_pred =
ecx.instantiate_binder_with_infer(poly_trait_pred);
ecx.instantiate_binder_with_infer(trait_clause);
ecx.eq(
goal.param_env,
goal.predicate.trait_ref,
@ -618,7 +618,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
| ty::Placeholder(..) => Some(Err(NoSolution)),
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),

View file

@ -0,0 +1,19 @@
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty;
use super::EvalCtxt;
impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn normalize_weak_type(
&mut self,
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
let weak_ty = goal.predicate.projection_ty;
let expected = goal.predicate.term.ty().expect("no such thing as a const alias");
let actual = tcx.type_of(weak_ty.def_id).subst(tcx, weak_ty.substs);
self.eq(goal.param_env, expected, actual)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}

View file

@ -292,7 +292,12 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
})
.chain(obligations)
.find(|o| !selcx.predicate_may_hold_fatal(o));
.find(|o| {
selcx.evaluate_root_obligation(o).map_or(
false, // Overflow has occurred, and treat the obligation as possibly holding.
|result| !result.may_apply(),
)
});
if let Some(failing_obligation) = opt_failing_obligation {
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@ -690,7 +695,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
| ty::RawPtr(..)
| ty::Never
| ty::Tuple(..)
| ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => {
self.found_non_local_ty(ty)
}
ty::Param(..) => self.found_param_ty(ty),

View file

@ -1824,12 +1824,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Alias(ty::Projection, ..) => Some(12),
ty::Alias(ty::Inherent, ..) => Some(13),
ty::Alias(ty::Opaque, ..) => Some(14),
ty::Never => Some(15),
ty::Adt(..) => Some(16),
ty::Generator(..) => Some(17),
ty::Foreign(..) => Some(18),
ty::GeneratorWitness(..) => Some(19),
ty::GeneratorWitnessMIR(..) => Some(20),
ty::Alias(ty::Weak, ..) => Some(15),
ty::Never => Some(16),
ty::Adt(..) => Some(17),
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
ty::GeneratorWitnessMIR(..) => Some(21),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}

View file

@ -3198,6 +3198,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
});
}
ObligationCauseCode::TypeAlias(ref nested, span, def_id) => {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
body_id,
err,
predicate,
param_env,
nested,
obligated_types,
seen_requirements,
)
});
let mut multispan = MultiSpan::from(span);
multispan.push_span_label(span, "required by this bound");
err.span_note(
multispan,
format!(
"required by a bound on the type alias `{}`",
self.infcx.tcx.item_name(def_id)
),
);
}
ObligationCauseCode::FunctionArgumentObligation {
arg_hir_id,
call_hir_id,

View file

@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId;
pub use rustc_middle::traits::query::OutlivesBound;
type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
pub trait InferCtxtExt<'a, 'tcx> {
fn implied_outlives_bounds(
&self,

View file

@ -3,6 +3,7 @@
use super::specialization_graph;
use super::translate_substs;
use super::util;
use super::ImplSourceUserDefinedData;
use super::MismatchedProjectionTypes;
use super::Obligation;
use super::ObligationCause;
@ -10,10 +11,6 @@ use super::PredicateObligation;
use super::Selection;
use super::SelectionContext;
use super::SelectionError;
use super::{
ImplSourceClosureData, ImplSourceFnPointerData, ImplSourceFutureData, ImplSourceGeneratorData,
ImplSourceUserDefinedData,
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
use crate::errors::InherentProjectionNormalizationOverflow;
@ -30,7 +27,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::at::At;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ImplSourceBuiltinData;
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
@ -621,6 +618,30 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
);
normalized_ty
}
ty::Weak => {
let infcx = self.selcx.infcx;
self.obligations.extend(
infcx
.tcx
.predicates_of(data.def_id)
.instantiate_own(infcx.tcx, data.substs)
.map(|(mut predicate, span)| {
if data.has_escaping_bound_vars() {
(predicate, ..) = BoundVarReplacer::replace_bound_vars(
infcx,
&mut self.universes,
predicate,
);
}
let mut cause = self.cause.clone();
cause.map_code(|code| {
ObligationCauseCode::TypeAlias(code, span, data.def_id)
});
Obligation::new(infcx.tcx, cause, self.param_env, predicate)
}),
);
infcx.tcx.type_of(data.def_id).subst(infcx.tcx, data.substs).fold_with(self)
}
ty::Inherent if !data.has_escaping_bound_vars() => {
// This branch is *mostly* just an optimization: when we don't
@ -1545,7 +1566,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
// Check whether the self-type is itself a projection.
// If so, extract what we know from the trait and try to come up with a good answer.
let bounds = match *obligation.predicate.self_ty().kind() {
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, ref data) => {
tcx.item_bounds(data.def_id).subst(tcx, data.substs)
}
@ -1696,11 +1717,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
};
let eligible = match &impl_source {
super::ImplSource::Closure(_)
| super::ImplSource::Generator(_)
| super::ImplSource::Future(_)
| super::ImplSource::FnPointer(_)
| super::ImplSource::TraitAlias(_) => true,
super::ImplSource::TraitAlias(_) => true,
super::ImplSource::UserDefined(impl_data) => {
// We have to be careful when projecting out of an
// impl because of specialization. If we are not in
@ -1758,7 +1775,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let lang_items = selcx.tcx().lang_items();
if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) {
if [lang_items.gen_trait(), lang_items.future_trait()].contains(&Some(poly_trait_ref.def_id()))
|| selcx.tcx().fn_trait_kind_from_def_id(poly_trait_ref.def_id()).is_some()
{
true
} else if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) {
match self_ty.kind() {
ty::Bool
| ty::Char
@ -1905,9 +1926,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// why we special case object types.
false
}
super::ImplSource::AutoImpl(..)
| super::ImplSource::TraitUpcasting(_)
| super::ImplSource::ConstDestruct(_) => {
| super::ImplSource::TraitUpcasting(_) => {
// These traits have no associated types.
selcx.tcx().sess.delay_span_bug(
obligation.cause.span,
@ -1971,17 +1990,27 @@ fn confirm_select_candidate<'cx, 'tcx>(
) -> Progress<'tcx> {
match impl_source {
super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data),
super::ImplSource::Future(data) => confirm_future_candidate(selcx, obligation, data),
super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data),
super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data),
super::ImplSource::Builtin(data) => confirm_builtin_candidate(selcx, obligation, data),
super::ImplSource::Builtin(data) => {
let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx());
let lang_items = selcx.tcx().lang_items();
if lang_items.gen_trait() == Some(trait_def_id) {
confirm_generator_candidate(selcx, obligation, data)
} else if lang_items.future_trait() == Some(trait_def_id) {
confirm_future_candidate(selcx, obligation, data)
} else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() {
if obligation.predicate.self_ty().is_closure() {
confirm_closure_candidate(selcx, obligation, data)
} else {
confirm_fn_pointer_candidate(selcx, obligation, data)
}
} else {
confirm_builtin_candidate(selcx, obligation, data)
}
}
super::ImplSource::Object(_)
| super::ImplSource::AutoImpl(..)
| super::ImplSource::Param(..)
| super::ImplSource::TraitUpcasting(_)
| super::ImplSource::TraitAlias(..)
| super::ImplSource::ConstDestruct(_) => {
| super::ImplSource::TraitAlias(..) => {
// we don't create Select candidates with this kind of resolution
span_bug!(
obligation.cause.span,
@ -1995,9 +2024,14 @@ fn confirm_select_candidate<'cx, 'tcx>(
fn confirm_generator_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
impl_source: ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let gen_sig = impl_source.substs.as_generator().poly_sig();
let ty::Generator(_, substs, _) =
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else {
unreachable!()
};
let gen_sig = substs.as_generator().poly_sig();
let Normalized { value: gen_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
@ -2035,16 +2069,21 @@ fn confirm_generator_candidate<'cx, 'tcx>(
});
confirm_param_env_candidate(selcx, obligation, predicate, false)
.with_addl_obligations(impl_source.nested)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
}
fn confirm_future_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
impl_source: ImplSourceFutureData<'tcx, PredicateObligation<'tcx>>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let gen_sig = impl_source.substs.as_generator().poly_sig();
let ty::Generator(_, substs, _) =
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else {
unreachable!()
};
let gen_sig = substs.as_generator().poly_sig();
let Normalized { value: gen_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
@ -2074,14 +2113,14 @@ fn confirm_future_candidate<'cx, 'tcx>(
});
confirm_param_env_candidate(selcx, obligation, predicate, false)
.with_addl_obligations(impl_source.nested)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
}
fn confirm_builtin_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
data: ImplSourceBuiltinData<PredicateObligation<'tcx>>,
data: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty();
@ -2129,15 +2168,15 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(obligations)
.with_addl_obligations(data.nested)
.with_addl_obligations(data)
}
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let fn_type = selcx.infcx.shallow_resolve(fn_pointer_impl_source.fn_ty);
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let sig = fn_type.fn_sig(selcx.tcx());
let Normalized { value: sig, obligations } = normalize_with_depth(
selcx,
@ -2148,16 +2187,21 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
);
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
.with_addl_obligations(fn_pointer_impl_source.nested)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
}
fn confirm_closure_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
impl_source: ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
let closure_sig = impl_source.substs.as_closure().sig();
let ty::Closure(_, substs) =
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else {
unreachable!()
};
let closure_sig = substs.as_closure().sig();
let Normalized { value: closure_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
@ -2169,7 +2213,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
.with_addl_obligations(impl_source.nested)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
}

View file

@ -257,7 +257,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
ty::Opaque => ty.try_super_fold_with(self)?,
ty::Projection | ty::Inherent => {
ty::Projection | ty::Inherent | ty::Weak => {
// See note in `rustc_trait_selection::traits::project`
let infcx = self.infcx;
@ -282,6 +282,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let result = match kind {
ty::Projection => tcx.normalize_projection_ty(c_data),
ty::Weak => tcx.normalize_weak_ty(c_data),
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
_ => unreachable!(),
}?;

View file

@ -143,7 +143,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Before we go into the whole placeholder thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, _) => {}
ty::Infer(ty::TyVar(_)) => {
span_bug!(

View file

@ -27,11 +27,9 @@ use crate::traits::vtable::{
};
use crate::traits::{
BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceFutureData,
ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData,
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, Obligation,
ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError,
ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceTraitUpcastingData,
ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError,
TraitNotObjectSafe, TraitObligation, Unimplemented,
};
@ -72,7 +70,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
AutoImplCandidate => {
let data = self.confirm_auto_impl_candidate(obligation);
ImplSource::AutoImpl(data)
ImplSource::Builtin(data)
}
ProjectionCandidate(idx, constness) => {
@ -87,22 +85,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ClosureCandidate { .. } => {
let vtable_closure = self.confirm_closure_candidate(obligation)?;
ImplSource::Closure(vtable_closure)
ImplSource::Builtin(vtable_closure)
}
GeneratorCandidate => {
let vtable_generator = self.confirm_generator_candidate(obligation)?;
ImplSource::Generator(vtable_generator)
ImplSource::Builtin(vtable_generator)
}
FutureCandidate => {
let vtable_future = self.confirm_future_candidate(obligation)?;
ImplSource::Future(vtable_future)
ImplSource::Builtin(vtable_future)
}
FnPointerCandidate { is_const } => {
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
ImplSource::FnPointer(data)
ImplSource::Builtin(data)
}
TraitAliasCandidate => {
@ -114,7 +112,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// This indicates something like `Trait + Send: Send`. In this case, we know that
// this holds because that's what the object type is telling us, and there's really
// no additional obligations to prove and no types in particular to unify, etc.
ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst)
ImplSource::Builtin(Vec::new())
}
BuiltinUnsizeCandidate => {
@ -129,7 +127,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ConstDestructCandidate(def_id) => {
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
ImplSource::ConstDestruct(data)
ImplSource::Builtin(data)
}
};
@ -163,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
(def_id, substs)
}
@ -244,7 +242,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
obligation: &TraitObligation<'tcx>,
has_nested: bool,
) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> {
) -> Vec<PredicateObligation<'tcx>> {
debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
let lang_items = self.tcx().lang_items();
@ -277,14 +275,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligations);
ImplSourceBuiltinData { nested: obligations }
obligations
}
#[instrument(level = "debug", skip(self))]
fn confirm_transmutability_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
use rustc_transmute::{Answer, Condition};
#[instrument(level = "debug", skip(tcx, obligation, predicate))]
fn flatten_answer_tree<'tcx>(
@ -369,7 +367,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
debug!(?fully_flattened);
Ok(ImplSourceBuiltinData { nested: fully_flattened })
Ok(fully_flattened)
}
/// This handles the case where an `auto trait Foo` impl is being used.
@ -380,7 +378,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_auto_impl_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
) -> Vec<PredicateObligation<'tcx>> {
debug!(?obligation, "confirm_auto_impl_candidate");
let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
@ -394,7 +392,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>,
trait_def_id: DefId,
nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
) -> Vec<PredicateObligation<'tcx>> {
debug!(?nested, "vtable_auto_impl");
ensure_sufficient_stack(|| {
let cause = obligation.derived_cause(BuiltinDerivedObligation);
@ -424,7 +422,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligations, "vtable_auto_impl");
ImplSourceAutoImplData { trait_def_id, nested: obligations }
obligations
})
}
@ -487,7 +485,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
obligation: &TraitObligation<'tcx>,
index: usize,
) -> Result<ImplSourceObjectData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
) -> Result<ImplSourceObjectData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx();
debug!(?obligation, ?index, "confirm_object_candidate");
@ -654,15 +652,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
);
Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
Ok(ImplSourceObjectData {
upcast_trait_def_id: upcast_trait_ref.def_id(),
vtable_base,
nested,
})
}
fn confirm_fn_pointer_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
is_const: bool,
) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_fn_pointer_candidate");
let tcx = self.tcx();
@ -714,7 +715,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tr = ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [output_ty]);
nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr));
Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested })
Ok(nested)
}
fn confirm_trait_alias_candidate(
@ -746,8 +747,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_generator_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Result<ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
// Okay to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
@ -780,13 +780,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
debug!(?trait_ref, ?nested, "generator candidate obligations");
Ok(ImplSourceGeneratorData { generator_def_id, substs, nested })
Ok(nested)
}
fn confirm_future_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Result<ImplSourceFutureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
// Okay to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
@ -810,14 +810,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
debug!(?trait_ref, ?nested, "future candidate obligations");
Ok(ImplSourceFutureData { generator_def_id, substs, nested })
Ok(nested)
}
#[instrument(skip(self), level = "debug")]
fn confirm_closure_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let kind = self
.tcx()
.fn_trait_kind_from_def_id(obligation.predicate.def_id())
@ -844,7 +844,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
));
}
Ok(ImplSourceClosureData { closure_def_id, substs, nested })
Ok(nested)
}
/// In the case of closure types and fn pointers,
@ -912,8 +912,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
obligation: &TraitObligation<'tcx>,
idx: usize,
) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
) -> Result<ImplSourceTraitUpcastingData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx();
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
@ -1010,13 +1009,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let vtable_vptr_slot =
prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap();
Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
Ok(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested })
}
fn confirm_builtin_unsize_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx();
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
@ -1217,17 +1216,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
_ => bug!("source: {source}, target: {target}"),
};
Ok(ImplSourceBuiltinData { nested })
Ok(nested)
}
fn confirm_const_destruct_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
impl_def_id: Option<DefId>,
) -> Result<ImplSourceConstDestructData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
// `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop`
if !obligation.is_const() {
return Ok(ImplSourceConstDestructData { nested: vec![] });
return Ok(vec![]);
}
let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);
@ -1381,6 +1380,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
Ok(ImplSourceConstDestructData { nested })
Ok(nested)
}
}

View file

@ -518,19 +518,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// The result is "true" if the obligation *may* hold and "false" if
// we can be sure it does not.
/// Evaluates whether the obligation `obligation` can be satisfied (by any means).
pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
debug!(?obligation, "predicate_may_hold_fatal");
// This fatal query is a stopgap that should only be used in standard mode,
// where we do not expect overflow to be propagated.
assert!(self.query_mode == TraitQueryMode::Standard);
self.evaluate_root_obligation(obligation)
.expect("Overflow should be caught earlier in standard query mode")
.may_apply()
}
/// Evaluates whether the obligation `obligation` can be satisfied
/// and returns an `EvaluationResult`. This is meant for the
/// *initial* call.
@ -2327,7 +2314,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
| ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble constituent types of unexpected type: {:?}", t);

View file

@ -243,12 +243,12 @@ pub fn upcast_choices<'tcx>(
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<'tcx, N>(
tcx: TyCtxt<'tcx>,
object: &super::ImplSourceObjectData<'tcx, N>,
object: &super::ImplSourceObjectData<N>,
method_def_id: DefId,
) -> Option<usize> {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
tcx.own_existential_vtable_entries(object.upcast_trait_ref.def_id())
tcx.own_existential_vtable_entries(object.upcast_trait_def_id)
.iter()
.copied()
.position(|def_id| def_id == method_def_id)

View file

@ -731,6 +731,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
}
ty::Alias(ty::Weak, ty::AliasTy { def_id, substs, .. }) => {
let obligations = self.nominal_obligations(def_id, substs);
self.out.extend(obligations);
}
ty::Dynamic(data, r, _) => {
// WfObject
//

View file

@ -372,6 +372,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
substitution: substs.lower_into(interner),
}))
}
ty::Alias(ty::Weak, ty::AliasTy { .. }) => unimplemented!(),
ty::Alias(ty::Inherent, _) => unimplemented!(),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {

View file

@ -10,7 +10,12 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
use std::sync::atomic::Ordering;
pub(crate) fn provide(p: &mut Providers) {
*p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p };
*p = Providers {
normalize_projection_ty,
normalize_weak_ty,
normalize_inherent_projection_ty,
..*p
};
}
fn normalize_projection_ty<'tcx>(
@ -43,6 +48,33 @@ fn normalize_projection_ty<'tcx>(
)
}
fn normalize_weak_ty<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalProjectionGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
debug!("normalize_provider(goal={:#?})", goal);
tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
|ocx, ParamEnvAnd { param_env, value: goal }| {
let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.substs).map(
|(predicate, span)| {
traits::Obligation::new(
tcx,
ObligationCause::dummy_with_span(span),
param_env,
predicate,
)
},
);
ocx.register_obligations(obligations);
let normalized_ty = tcx.type_of(goal.def_id).subst(tcx, goal.substs);
Ok(NormalizationResult { normalized_ty })
},
)
}
fn normalize_inherent_projection_ty<'tcx>(
tcx: TyCtxt<'tcx>,
goal: CanonicalProjectionGoal<'tcx>,

View file

@ -177,85 +177,6 @@ fn resolve_associated_item<'tcx>(
Some(ty::Instance::new(leaf_def.item.def_id, substs))
}
traits::ImplSource::Generator(generator_data) => {
if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
// For compiler developers who'd like to add new items to `Generator`,
// you either need to generate a shim body, or perhaps return
// `InstanceDef::Item` pointing to a trait default method body if
// it is given a default implementation by the trait.
span_bug!(
tcx.def_span(generator_data.generator_def_id),
"no definition for `{trait_ref}::{}` for built-in generator type",
tcx.item_name(trait_item_id)
)
}
Some(Instance {
def: ty::InstanceDef::Item(generator_data.generator_def_id),
substs: generator_data.substs,
})
}
traits::ImplSource::Future(future_data) => {
if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
// `Future::poll` is generated by the compiler.
Some(Instance {
def: ty::InstanceDef::Item(future_data.generator_def_id),
substs: future_data.substs,
})
} else {
// All other methods are default methods of the `Future` trait.
// (this assumes that `ImplSource::Future` is only used for methods on `Future`)
debug_assert!(tcx.defaultness(trait_item_id).has_value());
Some(Instance::new(trait_item_id, rcvr_substs))
}
}
traits::ImplSource::Closure(closure_data) => {
if cfg!(debug_assertions)
&& ![sym::call, sym::call_mut, sym::call_once]
.contains(&tcx.item_name(trait_item_id))
{
// For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
// you either need to generate a shim body, or perhaps return
// `InstanceDef::Item` pointing to a trait default method body if
// it is given a default implementation by the trait.
span_bug!(
tcx.def_span(closure_data.closure_def_id),
"no definition for `{trait_ref}::{}` for built-in closure type",
tcx.item_name(trait_item_id)
)
}
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
Instance::resolve_closure(
tcx,
closure_data.closure_def_id,
closure_data.substs,
trait_closure_kind,
)
}
traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
ty::FnDef(..) | ty::FnPtr(..) => {
if cfg!(debug_assertions)
&& ![sym::call, sym::call_mut, sym::call_once]
.contains(&tcx.item_name(trait_item_id))
{
// For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
// you either need to generate a shim body, or perhaps return
// `InstanceDef::Item` pointing to a trait default method body if
// it is given a default implementation by the trait.
bug!(
"no definition for `{trait_ref}::{}` for built-in fn type",
tcx.item_name(trait_item_id)
)
}
Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
substs: rcvr_substs,
})
}
_ => bug!(
"no built-in definition for `{trait_ref}::{}` for non-fn type",
tcx.item_name(trait_item_id)
),
},
traits::ImplSource::Object(ref data) => {
traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| {
Instance {
@ -308,15 +229,73 @@ fn resolve_associated_item<'tcx>(
span: tcx.def_span(trait_item_id),
})
}
} else if Some(trait_ref.def_id) == lang_items.future_trait() {
let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else {
bug!()
};
if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
// `Future::poll` is generated by the compiler.
Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs: substs })
} else {
// All other methods are default methods of the `Future` trait.
// (this assumes that `ImplSource::Builtin` is only used for methods on `Future`)
debug_assert!(tcx.defaultness(trait_item_id).has_value());
Some(Instance::new(trait_item_id, rcvr_substs))
}
} else if Some(trait_ref.def_id) == lang_items.gen_trait() {
let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else {
bug!()
};
if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
// For compiler developers who'd like to add new items to `Generator`,
// you either need to generate a shim body, or perhaps return
// `InstanceDef::Item` pointing to a trait default method body if
// it is given a default implementation by the trait.
span_bug!(
tcx.def_span(generator_def_id),
"no definition for `{trait_ref}::{}` for built-in generator type",
tcx.item_name(trait_item_id)
)
}
Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs })
} else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() {
// FIXME: This doesn't check for malformed libcore that defines, e.g.,
// `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension
// methods.
if cfg!(debug_assertions)
&& ![sym::call, sym::call_mut, sym::call_once]
.contains(&tcx.item_name(trait_item_id))
{
// For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
// you either need to generate a shim body, or perhaps return
// `InstanceDef::Item` pointing to a trait default method body if
// it is given a default implementation by the trait.
bug!(
"no definition for `{trait_ref}::{}` for built-in callable type",
tcx.item_name(trait_item_id)
)
}
match *rcvr_substs.type_at(0).kind() {
ty::Closure(closure_def_id, substs) => {
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
Instance::resolve_closure(tcx, closure_def_id, substs, trait_closure_kind)
}
ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_substs.type_at(0)),
substs: rcvr_substs,
}),
_ => bug!(
"no built-in definition for `{trait_ref}::{}` for non-fn type",
tcx.item_name(trait_item_id)
),
}
} else {
None
}
}
traits::ImplSource::AutoImpl(..)
| traits::ImplSource::Param(..)
traits::ImplSource::Param(..)
| traits::ImplSource::TraitAlias(..)
| traits::ImplSource::TraitUpcasting(_)
| traits::ImplSource::ConstDestruct(_) => None,
| traits::ImplSource::TraitUpcasting(_) => None,
})
}

View file

@ -36,9 +36,17 @@ pub enum DynKind {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum AliasKind {
/// A projection `<Type as Trait>::AssocType`.
/// Can get normalized away if monomorphic enough.
Projection,
Inherent,
/// An opaque type (usually from `impl Trait` in type aliases or function return types)
/// Can only be normalized away in RevealAll mode
Opaque,
/// A type alias that actually checks its trait bounds.
/// Currently only used if the type alias references opaque types.
/// Can always be normalized away.
Weak,
}
/// Defines the kinds of types used by the type system.

View file

@ -56,6 +56,11 @@
//! [`Rc`]: rc
//! [`RefCell`]: core::cell
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
//
#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
@ -75,11 +80,6 @@
))]
#![no_std]
#![needs_allocator]
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
//
// Lints:
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]

View file

@ -32,6 +32,8 @@ use crate::ptr::NonNull;
)]
#[doc(hidden)]
#[repr(transparent)]
// Lang item used experimentally by Miri to define the semantics of `Unique`.
#[cfg_attr(not(bootstrap), lang = "ptr_unique")]
pub struct Unique<T: ?Sized> {
pointer: NonNull<T>,
// NOTE: this marker has no consequences for variance, but is necessary

View file

@ -47,9 +47,9 @@ use buffer::Buffer;
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> {
inner: R,
pub struct BufReader<R: ?Sized> {
buf: Buffer,
inner: R,
}
impl<R: Read> BufReader<R> {
@ -95,7 +95,7 @@ impl<R: Read> BufReader<R> {
}
}
impl<R> BufReader<R> {
impl<R: ?Sized> BufReader<R> {
/// Gets a reference to the underlying reader.
///
/// It is inadvisable to directly read from the underlying reader.
@ -213,7 +213,10 @@ impl<R> BufReader<R> {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> R {
pub fn into_inner(self) -> R
where
R: Sized,
{
self.inner
}
@ -226,13 +229,13 @@ impl<R> BufReader<R> {
// This is only used by a test which asserts that the initialization-tracking is correct.
#[cfg(test)]
impl<R> BufReader<R> {
impl<R: ?Sized> BufReader<R> {
pub fn initialized(&self) -> usize {
self.buf.initialized()
}
}
impl<R: Seek> BufReader<R> {
impl<R: ?Sized + Seek> BufReader<R> {
/// Seeks relative to the current position. If the new position lies within the buffer,
/// the buffer will not be flushed, allowing for more efficient seeks.
/// This method does not return the location of the underlying reader, so the caller
@ -257,7 +260,7 @@ impl<R: Seek> BufReader<R> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> Read for BufReader<R> {
impl<R: ?Sized + Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
@ -371,7 +374,7 @@ impl<R: Read> Read for BufReader<R> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> BufRead for BufReader<R> {
impl<R: ?Sized + Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.buf.fill_buf(&mut self.inner)
}
@ -384,11 +387,11 @@ impl<R: Read> BufRead for BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<R> fmt::Debug for BufReader<R>
where
R: fmt::Debug,
R: ?Sized + fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufReader")
.field("reader", &self.inner)
.field("reader", &&self.inner)
.field(
"buffer",
&format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
@ -398,7 +401,7 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Seek> Seek for BufReader<R> {
impl<R: ?Sized + Seek> Seek for BufReader<R> {
/// Seek to an offset, in bytes, in the underlying reader.
///
/// The position used for seeking with <code>[SeekFrom::Current]\(_)</code> is the
@ -491,7 +494,7 @@ impl<R: Seek> Seek for BufReader<R> {
}
}
impl<T> SizeHint for BufReader<T> {
impl<T: ?Sized> SizeHint for BufReader<T> {
#[inline]
fn lower_bound(&self) -> usize {
SizeHint::lower_bound(self.get_ref()) + self.buffer().len()

View file

@ -67,8 +67,7 @@ use crate::ptr;
/// [`TcpStream`]: crate::net::TcpStream
/// [`flush`]: BufWriter::flush
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: Write> {
inner: W,
pub struct BufWriter<W: ?Sized + Write> {
// The buffer. Avoid using this like a normal `Vec` in common code paths.
// That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
// methods that require bounds checking or the like. This makes an enormous
@ -78,6 +77,7 @@ pub struct BufWriter<W: Write> {
// write the buffered data a second time in BufWriter's destructor. This
// flag tells the Drop impl if it should skip the flush.
panicked: bool,
inner: W,
}
impl<W: Write> BufWriter<W> {
@ -115,6 +115,69 @@ impl<W: Write> BufWriter<W> {
BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false }
}
/// Unwraps this `BufWriter<W>`, returning the underlying writer.
///
/// The buffer is written out before returning the writer.
///
/// # Errors
///
/// An [`Err`] will be returned if an error occurs while flushing the buffer.
///
/// # Examples
///
/// ```no_run
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // unwrap the TcpStream and flush the buffer
/// let stream = buffer.into_inner().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
match self.flush_buf() {
Err(e) => Err(IntoInnerError::new(self, e)),
Ok(()) => Ok(self.into_parts().0),
}
}
/// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
/// unwritten data.
///
/// If the underlying writer panicked, it is not known what portion of the data was written.
/// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
/// contents can still be recovered).
///
/// `into_parts` makes no attempt to flush data and cannot fail.
///
/// # Examples
///
/// ```
/// use std::io::{BufWriter, Write};
///
/// let mut buffer = [0u8; 10];
/// let mut stream = BufWriter::new(buffer.as_mut());
/// write!(stream, "too much data").unwrap();
/// stream.flush().expect_err("it doesn't fit");
/// let (recovered_writer, buffered_data) = stream.into_parts();
/// assert_eq!(recovered_writer.len(), 0);
/// assert_eq!(&buffered_data.unwrap(), b"ata");
/// ```
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
let buf = mem::take(&mut self.buf);
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
// SAFETY: forget(self) prevents double dropping inner
let inner = unsafe { ptr::read(&self.inner) };
mem::forget(self);
(inner, buf)
}
}
impl<W: ?Sized + Write> BufWriter<W> {
/// Send data in our local buffer into the inner writer, looping as
/// necessary until either it's all been sent or an error occurs.
///
@ -284,67 +347,6 @@ impl<W: Write> BufWriter<W> {
self.buf.capacity()
}
/// Unwraps this `BufWriter<W>`, returning the underlying writer.
///
/// The buffer is written out before returning the writer.
///
/// # Errors
///
/// An [`Err`] will be returned if an error occurs while flushing the buffer.
///
/// # Examples
///
/// ```no_run
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // unwrap the TcpStream and flush the buffer
/// let stream = buffer.into_inner().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
match self.flush_buf() {
Err(e) => Err(IntoInnerError::new(self, e)),
Ok(()) => Ok(self.into_parts().0),
}
}
/// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
/// unwritten data.
///
/// If the underlying writer panicked, it is not known what portion of the data was written.
/// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
/// contents can still be recovered).
///
/// `into_parts` makes no attempt to flush data and cannot fail.
///
/// # Examples
///
/// ```
/// use std::io::{BufWriter, Write};
///
/// let mut buffer = [0u8; 10];
/// let mut stream = BufWriter::new(buffer.as_mut());
/// write!(stream, "too much data").unwrap();
/// stream.flush().expect_err("it doesn't fit");
/// let (recovered_writer, buffered_data) = stream.into_parts();
/// assert_eq!(recovered_writer.len(), 0);
/// assert_eq!(&buffered_data.unwrap(), b"ata");
/// ```
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
let buf = mem::take(&mut self.buf);
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
// SAFETY: forget(self) prevents double dropping inner
let inner = unsafe { ptr::read(&self.inner) };
mem::forget(self);
(inner, buf)
}
// Ensure this function does not get inlined into `write`, so that it
// remains inlineable and its common path remains as short as possible.
// If this function ends up being called frequently relative to `write`,
@ -511,7 +513,7 @@ impl fmt::Debug for WriterPanicked {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Write for BufWriter<W> {
impl<W: ?Sized + Write> Write for BufWriter<W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Use < instead of <= to avoid a needless trip through the buffer in some cases.
@ -640,20 +642,20 @@ impl<W: Write> Write for BufWriter<W> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> fmt::Debug for BufWriter<W>
impl<W: ?Sized + Write> fmt::Debug for BufWriter<W>
where
W: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufWriter")
.field("writer", &self.inner)
.field("writer", &&self.inner)
.field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
.finish()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write + Seek> Seek for BufWriter<W> {
impl<W: ?Sized + Write + Seek> Seek for BufWriter<W> {
/// Seek to the offset, in bytes, in the underlying writer.
///
/// Seeking always writes out the internal buffer before seeking.
@ -664,7 +666,7 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Drop for BufWriter<W> {
impl<W: ?Sized + Write> Drop for BufWriter<W> {
fn drop(&mut self) {
if !self.panicked {
// dtors should not panic, so we ignore a failed flush

View file

@ -64,7 +64,7 @@ use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSli
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LineWriter<W: Write> {
pub struct LineWriter<W: ?Sized + Write> {
inner: BufWriter<W>,
}
@ -109,27 +109,6 @@ impl<W: Write> LineWriter<W> {
LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
}
/// Gets a reference to the underlying writer.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::io::LineWriter;
///
/// fn main() -> std::io::Result<()> {
/// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
///
/// let reference = file.get_ref();
/// Ok(())
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &W {
self.inner.get_ref()
}
/// Gets a mutable reference to the underlying writer.
///
/// Caution must be taken when calling methods on the mutable reference
@ -184,8 +163,31 @@ impl<W: Write> LineWriter<W> {
}
}
impl<W: ?Sized + Write> LineWriter<W> {
/// Gets a reference to the underlying writer.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::io::LineWriter;
///
/// fn main() -> std::io::Result<()> {
/// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
///
/// let reference = file.get_ref();
/// Ok(())
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &W {
self.inner.get_ref()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Write for LineWriter<W> {
impl<W: ?Sized + Write> Write for LineWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
LineWriterShim::new(&mut self.inner).write(buf)
}
@ -216,7 +218,7 @@ impl<W: Write> Write for LineWriter<W> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> fmt::Debug for LineWriter<W>
impl<W: ?Sized + Write> fmt::Debug for LineWriter<W>
where
W: fmt::Debug,
{

View file

@ -11,11 +11,11 @@ use crate::sys_common::memchr;
/// `BufWriters` to be temporarily given line-buffering logic; this is what
/// enables Stdout to be alternately in line-buffered or block-buffered mode.
#[derive(Debug)]
pub struct LineWriterShim<'a, W: Write> {
pub struct LineWriterShim<'a, W: ?Sized + Write> {
buffer: &'a mut BufWriter<W>,
}
impl<'a, W: Write> LineWriterShim<'a, W> {
impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
Self { buffer }
}
@ -49,7 +49,7 @@ impl<'a, W: Write> LineWriterShim<'a, W> {
}
}
impl<'a, W: Write> Write for LineWriterShim<'a, W> {
impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
/// Write some data into this BufReader with line buffering. This means
/// that, if any newlines are present in the data, the data up to the last
/// newline is sent directly to the underlying writer, and data after it

View file

@ -86,7 +86,7 @@ impl<W: Write + ?Sized> BufferedCopySpec for W {
}
}
impl<I: Write> BufferedCopySpec for BufWriter<I> {
impl<I: ?Sized + Write> BufferedCopySpec for BufWriter<I> {
fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
if writer.capacity() < DEFAULT_BUF_SIZE {
return stack_buffer_copy(reader, writer);

View file

@ -2754,7 +2754,7 @@ trait SizeHint {
}
}
impl<T> SizeHint for T {
impl<T: ?Sized> SizeHint for T {
#[inline]
default fn lower_bound(&self) -> usize {
0

View file

@ -188,6 +188,13 @@
//! [array]: prim@array
//! [slice]: prim@slice
// To run std tests without x.py without ending up with two copies of std, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
//
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
@ -202,12 +209,6 @@
no_global_oom_handling,
not(no_global_oom_handling)
))]
// To run std tests without x.py without ending up with two copies of std, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
// Don't link to std. We are std.
#![no_std]
// Tell the compiler to link to either panic_abort or panic_unwind

View file

@ -17,6 +17,7 @@ mod libc {
pub use libc::c_int;
pub struct ucred;
pub struct cmsghdr;
pub struct sockcred2;
pub type pid_t = i32;
pub type gid_t = u32;
pub type uid_t = u32;

View file

@ -466,7 +466,7 @@ impl<T: CopyRead> CopyRead for Take<T> {
}
}
impl<T: CopyRead> CopyRead for BufReader<T> {
impl<T: ?Sized + CopyRead> CopyRead for BufReader<T> {
fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
let buf = self.buffer();
let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
@ -495,7 +495,7 @@ impl<T: CopyRead> CopyRead for BufReader<T> {
}
}
impl<T: CopyWrite> CopyWrite for BufWriter<T> {
impl<T: ?Sized + CopyWrite> CopyWrite for BufWriter<T> {
fn properties(&self) -> CopyParams {
self.get_ref().properties()
}

View file

@ -344,6 +344,29 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
}
}
#[cfg(target_os = "netbsd")]
{
unsafe {
let set = libc::_cpuset_create();
if !set.is_null() {
let mut count: usize = 0;
if libc::pthread_getaffinity_np(libc::pthread_self(), libc::_cpuset_size(set), set) == 0 {
for i in 0..u64::MAX {
match libc::_cpuset_isset(i, set) {
-1 => break,
0 => continue,
_ => count = count + 1,
}
}
}
libc::_cpuset_destroy(set);
if let Some(count) = NonZeroUsize::new(count) {
return Ok(count);
}
}
}
}
let mut cpus: libc::c_uint = 0;
let mut cpus_size = crate::mem::size_of_val(&cpus);

View file

@ -45,6 +45,9 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
python3 ../x.py test --stage 0 src/tools/compiletest && \
python3 ../x.py test --stage 0 core alloc std test proc_macro && \
# Build both public and internal documentation.
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library && \
mkdir -p /checkout/obj/staging/doc && \
cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
/scripts/validate-toolstate.sh && \

View file

@ -34,6 +34,8 @@ x--expand-yaml-anchors--remove:
- &shared-ci-variables
CI_JOB_NAME: ${{ matrix.name }}
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
# commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs.
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
- &public-variables
SCCACHE_BUCKET: rust-lang-ci-sccache2
@ -229,6 +231,20 @@ x--expand-yaml-anchors--remove:
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
<<: *step
- name: create github artifacts
run: src/ci/scripts/create-doc-artifacts.sh
<<: *step
- name: upload artifacts to github
uses: actions/upload-artifact@v3
with:
# name is set in previous step
name: ${{ env.DOC_ARTIFACT_NAME }}
path: obj/artifacts/doc
if-no-files-found: ignore
retention-days: 5
<<: *step
- name: upload artifacts to S3
run: src/ci/scripts/upload-artifacts.sh
env:

View file

@ -0,0 +1,42 @@
#!/bin/bash
# Compress doc artifacts and name them based on the commit, or the date if
# commit is not available.
set -euox pipefail
# Try to get short commit hash, fallback to date
if [ -n "$HEAD_SHA" ]; then
short_rev=$(echo "${HEAD_SHA}" | cut -c1-8)
else
short_rev=$(git rev-parse --short HEAD || date -u +'%Y-%m-%dT%H%M%SZ')
fi
# Try to get branch, fallback to none
branch=$(git branch --show-current || echo)
if [ -n "$branch" ]; then
branch="${branch}-"
fi
if [ "${GITHUB_EVENT_NAME:=none}" = "pull_request" ]; then
pr_num=$(echo "$GITHUB_REF_NAME" | cut -d'/' -f1)
name="doc-${pr_num}-${short_rev}"
else
name="doc-${branch}${short_rev}"
fi
if [ -d "obj/staging/doc" ]; then
mkdir -p obj/artifacts/doc
# Level 12 seems to give a good tradeoff of time vs. space savings
ZSTD_CLEVEL=12 ZSTD_NBTHREADS=4 \
tar --zstd -cf "obj/artifacts/doc/${name}.tar.zst" -C obj/staging/doc .
ls -lh obj/artifacts/doc
fi
# Set this environment variable for future use if running in CI
if [ -n "$GITHUB_ENV" ]; then
echo "DOC_ARTIFACT_NAME=${name}" >> "$GITHUB_ENV"
fi

View file

@ -2052,6 +2052,11 @@ pub(crate) fn clean_middle_ty<'tcx>(
}))
}
ty::Alias(ty::Weak, data) => {
let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs);
clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
}
ty::Param(ref p) => {
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
ImplTrait(bounds)

View file

@ -800,10 +800,11 @@ fn assoc_type(
if !bounds.is_empty() {
write!(w, ": {}", print_generic_bounds(bounds, cx))
}
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
// Render the default before the where-clause which aligns with the new recommended style. See #89122.
if let Some(default) = default {
write!(w, " = {}", default.print(cx))
}
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
}
fn assoc_method(

View file

@ -213,7 +213,7 @@ a.anchor,
h1 a,
.search-results a,
.stab,
.result-name .primitive > i, .result-name .keyword > i {
.result-name i {
color: var(--main-color);
}
@ -887,7 +887,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
.search-results .result-name span.alias {
color: var(--search-results-alias-color);
}
.search-results .result-name span.grey {
.search-results .result-name .grey {
color: var(--search-results-grey-color);
}

View file

@ -35,6 +35,35 @@ const itemTypes = [
"traitalias",
];
const longItemTypes = [
"module",
"extern crate",
"re-export",
"struct",
"enum",
"function",
"type alias",
"static",
"trait",
"",
"trait method",
"method",
"struct field",
"enum variant",
"macro",
"primitive type",
"associated type",
"constant",
"associated constant",
"union",
"foreign type",
"keyword",
"existential type",
"attribute macro",
"derive macro",
"trait alias",
];
// used for special search precedence
const TY_PRIMITIVE = itemTypes.indexOf("primitive");
const TY_KEYWORD = itemTypes.indexOf("keyword");
@ -1966,16 +1995,11 @@ function initSearch(rawSearchIndex) {
array.forEach(item => {
const name = item.name;
const type = itemTypes[item.ty];
const longType = longItemTypes[item.ty];
const typeName = longType.length !== 0 ? `${longType}` : "?";
length += 1;
let extra = "";
if (type === "primitive") {
extra = " <i>(primitive type)</i>";
} else if (type === "keyword") {
extra = " <i>(keyword)</i>";
}
const link = document.createElement("a");
link.className = "result-" + type;
link.href = item.href;
@ -1993,13 +2017,14 @@ function initSearch(rawSearchIndex) {
alias.insertAdjacentHTML(
"beforeend",
"<span class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>");
"<i class=\"grey\">&nbsp;- see&nbsp;</i>");
resultName.appendChild(alias);
}
resultName.insertAdjacentHTML(
"beforeend",
item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
`${typeName} ${item.displayPath}<span class="${type}">${name}</span>`);
link.appendChild(resultName);
const description = document.createElement("div");

View file

@ -1424,6 +1424,7 @@ fn ty_auto_deref_stability<'tcx>(
continue;
},
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
ty::Alias(ty::Weak, _) => unreachable!("should have been normalized away above"),
ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
TyPosition::new_deref_stable_for_result(precedence, ty)

View file

@ -82,10 +82,4 @@ fn msrv_1_41() {
}
}
type Opaque = impl Sized;
struct IntoOpaque;
impl Into<Opaque> for IntoOpaque {
fn into(self) -> Opaque {}
}
fn main() {}

View file

@ -82,10 +82,4 @@ fn msrv_1_41() {
}
}
type Opaque = impl Sized;
struct IntoOpaque;
impl Into<Opaque> for IntoOpaque {
fn into(self) -> Opaque {}
}
fn main() {}

View file

@ -32,4 +32,10 @@ impl Into<u8> for ContainsVal {
}
}
type Opaque = impl Sized;
struct IntoOpaque;
impl Into<Opaque> for IntoOpaque {
fn into(self) -> Opaque {}
}
fn main() {}

View file

@ -1,29 +1,12 @@
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
--> $DIR/from_over_into_unfixable.rs:11:1
error[E0658]: `impl Trait` in type aliases is unstable
--> $DIR/from_over_into_unfixable.rs:35:15
|
LL | impl Into<InMacro> for String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | type Opaque = impl Sized;
| ^^^^^^^^^^
|
= help: replace the `Into` implementation with `From<std::string::String>`
= note: `-D clippy::from-over-into` implied by `-D warnings`
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
--> $DIR/from_over_into_unfixable.rs:19:1
|
LL | impl Into<WeirdUpperSelf> for &'static [u8] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: replace the `Into` implementation with `From<&'static [u8]>`
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
--> $DIR/from_over_into_unfixable.rs:28:1
|
LL | impl Into<u8> for ContainsVal {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
= help: replace the `Into` implementation with `From<ContainsVal>`
error: aborting due to 3 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -401,25 +401,3 @@ mod issue7344 {
}
}
}
mod issue10041 {
struct Bomb;
impl Bomb {
// Hidden <Rhs = Self> default generic parameter.
pub fn new() -> impl PartialOrd {
0i32
}
}
// TAIT with self-referencing bounds
type X = impl std::ops::Add<Output = X>;
struct Bomb2;
impl Bomb2 {
pub fn new() -> X {
0i32
}
}
}

View file

@ -92,21 +92,5 @@ LL | | unimplemented!()
LL | | }
| |_________^
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:410:9
|
LL | / pub fn new() -> impl PartialOrd {
LL | | 0i32
LL | | }
| |_________^
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:421:9
|
LL | / pub fn new() -> X {
LL | | 0i32
LL | | }
| |_________^
error: aborting due to 14 previous errors
error: aborting due to 12 previous errors

View file

@ -0,0 +1,26 @@
#![feature(type_alias_impl_trait)]
#![warn(clippy::new_ret_no_self)]
mod issue10041 {
struct Bomb;
impl Bomb {
// Hidden <Rhs = Self> default generic parameter.
pub fn new() -> impl PartialOrd {
0i32
}
}
// TAIT with self-referencing bounds
type X = impl std::ops::Add<Output = X>;
struct Bomb2;
impl Bomb2 {
pub fn new() -> X {
0i32
}
}
}
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0275]: overflow evaluating the requirement `<i32 as std::ops::Add>::Output == issue10041::X`
--> $DIR/new_ret_no_self_overflow.rs:20:25
|
LL | pub fn new() -> X {
| ^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0275`.

View file

@ -1,4 +1,4 @@
//@compile-flags: -Zmir-opt-level=3
//@compile-flags: -Zmir-opt-level=3 -Zinline-mir-hint-threshold=1000
// Enable MIR inlining to ensure that `TerminatorKind::Terminate` is generated
// instead of just `UnwindAction::Terminate`.

View file

@ -7,8 +7,8 @@
// compile-flags: -g -C no-prepopulate-passes
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}}
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i64 4294967295{{[,)].*}}
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}}
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i128 4294967295{{[,)].*}}
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i128 0{{[,)].*}}
#![feature(never_type)]

View file

@ -0,0 +1,27 @@
// This tests that debug info for "c-like" 128bit enums is properly emitted.
// This is ignored for the fallback mode on MSVC due to problems with PDB.
//
// ignore-msvc
// compile-flags: -g -C no-prepopulate-passes
// CHECK-LABEL: @main
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "Foo",{{.*}}flags: DIFlagEnumClass,{{.*}}
// CHECK: {{.*}}DIEnumerator{{.*}}name: "Lo",{{.*}}value: 0,{{.*}}
// CHECK: {{.*}}DIEnumerator{{.*}}name: "Hi",{{.*}}value: 18446744073709551616,{{.*}}
// CHECK: {{.*}}DIEnumerator{{.*}}name: "Bar",{{.*}}value: 18446745000000000123,{{.*}}
#![allow(incomplete_features)]
#![feature(repr128)]
#[repr(u128)]
pub enum Foo {
Lo,
Hi = 1 << 64,
Bar = 18_446_745_000_000_000_123,
}
pub fn main() {
let foo = Foo::Bar;
}

View file

@ -2,6 +2,7 @@
//
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// needs-asm-support
// compile-flags: -Zinline-mir-hint-threshold=1000
#![feature(asm_unwind)]
struct D;
@ -10,7 +11,7 @@ impl Drop for D {
fn drop(&mut self) {}
}
#[inline(always)]
#[inline]
fn foo() {
let _d = D;
unsafe { std::arch::asm!("", options(may_unwind)) };

View file

@ -1,4 +1,5 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// compile-flags: -Zinline-mir-hint-threshold=1000
// EMIT_MIR cycle.f.Inline.diff
#[inline(always)]

Some files were not shown because too many files have changed in this diff Show more