Merge from rustc
This commit is contained in:
commit
48440b1403
80 changed files with 1940 additions and 1419 deletions
File diff suppressed because it is too large
Load diff
|
@ -26,7 +26,7 @@ mod layout;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use layout::LayoutCalculator;
|
||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
|
@ -393,6 +393,14 @@ impl HasDataLayout for TargetDataLayout {
|
|||
}
|
||||
}
|
||||
|
||||
// used by rust-analyzer
|
||||
impl HasDataLayout for &TargetDataLayout {
|
||||
#[inline]
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
(**self).data_layout()
|
||||
}
|
||||
}
|
||||
|
||||
/// Endianness of the target, which must match cfg(target-endian).
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Endian {
|
||||
|
|
|
@ -2066,14 +2066,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
};
|
||||
}
|
||||
|
||||
arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, 0.0);
|
||||
arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, -0.0);
|
||||
arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0);
|
||||
arith_red!(
|
||||
simd_reduce_add_unordered: vector_reduce_add,
|
||||
vector_reduce_fadd_reassoc,
|
||||
false,
|
||||
add,
|
||||
0.0
|
||||
-0.0
|
||||
);
|
||||
arith_red!(
|
||||
simd_reduce_mul_unordered: vector_reduce_mul,
|
||||
|
|
|
@ -7,7 +7,9 @@ use std::{env, iter, mem, str};
|
|||
|
||||
use cc::windows_registry;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_metadata::{find_native_static_library, try_find_native_static_library};
|
||||
use rustc_metadata::{
|
||||
find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols;
|
||||
|
@ -876,7 +878,13 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
}
|
||||
|
||||
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
|
||||
self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
|
||||
// On MSVC-like targets rustc supports import libraries using alternative naming
|
||||
// scheme (`libfoo.a`) unsupported by linker, search for such libraries manually.
|
||||
if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
|
||||
self.link_arg(path);
|
||||
} else {
|
||||
self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
|
||||
}
|
||||
}
|
||||
|
||||
fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
|
||||
|
|
|
@ -319,7 +319,7 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
let branches = valtree.unwrap_branch();
|
||||
// Find the non-ZST field. (There can be aligned ZST!)
|
||||
for (i, &inner_valtree) in branches.iter().enumerate() {
|
||||
let field = layout.field(&LayoutCx { tcx, param_env }, i);
|
||||
let field = layout.field(&LayoutCx::new(tcx, param_env), i);
|
||||
if !field.is_zst() {
|
||||
return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc_middle::mir::interpret::{
|
|||
UnsupportedOpInfo, ValidationErrorInfo,
|
||||
};
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_target::abi::{
|
||||
Abi, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
|
||||
|
@ -940,7 +940,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||
) -> Cow<'e, RangeSet> {
|
||||
assert!(layout.ty.is_union());
|
||||
assert!(layout.abi.is_sized(), "there are no unsized unions");
|
||||
let layout_cx = LayoutCx { tcx: *ecx.tcx, param_env: ecx.param_env };
|
||||
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
|
||||
return M::cached_union_data_range(ecx, layout.ty, || {
|
||||
let mut out = RangeSet(Vec::new());
|
||||
union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out);
|
||||
|
@ -949,7 +949,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||
|
||||
/// Helper for recursive traversal: add data ranges of the given type to `out`.
|
||||
fn union_data_range_uncached<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
base_offset: Size,
|
||||
out: &mut RangeSet,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::layout::{
|
||||
HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement,
|
||||
};
|
||||
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||
|
||||
|
@ -30,7 +32,7 @@ pub fn check_validity_requirement<'tcx>(
|
|||
return Ok(!layout.abi.is_uninhabited());
|
||||
}
|
||||
|
||||
let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
|
||||
let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
|
||||
if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
check_validity_requirement_strict(layout, &layout_cx, kind)
|
||||
} else {
|
||||
|
@ -42,12 +44,12 @@ pub fn check_validity_requirement<'tcx>(
|
|||
/// for details.
|
||||
fn check_validity_requirement_strict<'tcx>(
|
||||
ty: TyAndLayout<'tcx>,
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
kind: ValidityRequirement,
|
||||
) -> Result<bool, &'tcx LayoutError<'tcx>> {
|
||||
let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
|
||||
|
||||
let mut cx = InterpCx::new(cx.tcx, rustc_span::DUMMY_SP, cx.param_env, machine);
|
||||
let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.param_env, machine);
|
||||
|
||||
let allocated = cx
|
||||
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
|
@ -80,7 +82,7 @@ fn check_validity_requirement_strict<'tcx>(
|
|||
/// function for details.
|
||||
fn check_validity_requirement_lax<'tcx>(
|
||||
this: TyAndLayout<'tcx>,
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
init_kind: ValidityRequirement,
|
||||
) -> Result<bool, &'tcx LayoutError<'tcx>> {
|
||||
let scalar_allows_raw_init = move |s: Scalar| -> bool {
|
||||
|
|
19
compiler/rustc_error_codes/src/error_codes/E0799.md
Normal file
19
compiler/rustc_error_codes/src/error_codes/E0799.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
Something other than a type or const parameter has been used when one was
|
||||
expected.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0799
|
||||
fn bad1() -> impl Sized + use<main> {}
|
||||
|
||||
fn bad2(x: ()) -> impl Sized + use<x> {}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
In the given examples, for `bad1`, the name `main` corresponds to a function
|
||||
rather than a type or const parameter. In `bad2`, the name `x` corresponds to
|
||||
a function argument rather than a type or const parameter.
|
||||
|
||||
Only type and const parameters, including `Self`, may be captured by
|
||||
`use<...>` precise capturing bounds.
|
11
compiler/rustc_error_codes/src/error_codes/E0800.md
Normal file
11
compiler/rustc_error_codes/src/error_codes/E0800.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
A type or const parameter of the given name is not in scope.
|
||||
|
||||
Erroneous code examples:
|
||||
|
||||
```compile_fail,E0800
|
||||
fn missing() -> impl Sized + use<T> {}
|
||||
```
|
||||
|
||||
To fix this error, please verify you didn't misspell the type or const
|
||||
parameter, or double-check if you forgot to declare the parameter in
|
||||
the list of generics.
|
|
@ -538,6 +538,8 @@ E0795: 0795,
|
|||
E0796: 0796,
|
||||
E0797: 0797,
|
||||
E0798: 0798,
|
||||
E0799: 0799,
|
||||
E0800: 0800,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
@ -726,7 +726,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
num_trait_args,
|
||||
num_impl_args,
|
||||
def_id,
|
||||
impl_def_id: impl_m.container_id(tcx),
|
||||
impl_m_def_id: impl_m.def_id,
|
||||
ty,
|
||||
return_span,
|
||||
}) {
|
||||
|
@ -844,12 +844,18 @@ where
|
|||
|
||||
struct RemapHiddenTyRegions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
/// Map from early/late params of the impl to identity regions of the RPITIT (GAT)
|
||||
/// in the trait.
|
||||
map: FxIndexMap<ty::Region<'tcx>, ty::Region<'tcx>>,
|
||||
num_trait_args: usize,
|
||||
num_impl_args: usize,
|
||||
/// Def id of the RPITIT (GAT) in the *trait*.
|
||||
def_id: DefId,
|
||||
impl_def_id: DefId,
|
||||
/// Def id of the impl method which owns the opaque hidden type we're remapping.
|
||||
impl_m_def_id: DefId,
|
||||
/// The hidden type we're remapping. Useful for diagnostics.
|
||||
ty: Ty<'tcx>,
|
||||
/// Span of the return type. Useful for diagnostics.
|
||||
return_span: Span,
|
||||
}
|
||||
|
||||
|
@ -885,8 +891,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
|
|||
ty::ReLateParam(_) => {}
|
||||
// Remap early-bound regions as long as they don't come from the `impl` itself,
|
||||
// in which case we don't really need to renumber them.
|
||||
ty::ReEarlyParam(ebr)
|
||||
if ebr.index >= self.tcx.generics_of(self.impl_def_id).count() as u32 => {}
|
||||
ty::ReEarlyParam(ebr) if ebr.index as usize >= self.num_impl_args => {}
|
||||
_ => return Ok(region),
|
||||
}
|
||||
|
||||
|
@ -899,7 +904,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
let guar = match region.opt_param_def_id(self.tcx, self.tcx.parent(self.def_id)) {
|
||||
let guar = match region.opt_param_def_id(self.tcx, self.impl_m_def_id) {
|
||||
Some(def_id) => {
|
||||
let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() {
|
||||
self.tcx.def_span(opaque_ty.def_id)
|
||||
|
|
|
@ -584,7 +584,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
| Res::SelfTyParam { trait_: def_id } => {
|
||||
self.resolve_type_ref(def_id.expect_local(), param.hir_id);
|
||||
}
|
||||
Res::Err => {}
|
||||
Res::SelfTyAlias { alias_to, .. } => {
|
||||
self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias {
|
||||
span: param.ident.span,
|
||||
|
@ -593,11 +592,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
res => {
|
||||
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
|
||||
span: param.ident.span,
|
||||
kind: "type or const",
|
||||
found: res.descr().to_string(),
|
||||
});
|
||||
self.tcx.dcx().span_delayed_bug(
|
||||
param.ident.span,
|
||||
format!("expected type or const param, found {res:?}"),
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_errors::E0799;
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
|
@ -43,7 +44,7 @@ pub(crate) struct BadPreciseCapture {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_precise_capture_self_alias)]
|
||||
#[diag(hir_analysis_precise_capture_self_alias, code = E0799)]
|
||||
pub(crate) struct PreciseCaptureSelfAlias {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
|
@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// trait or region sub-obligations. (presumably we could, but it's not
|
||||
/// particularly important for diagnostics...)
|
||||
pub(crate) fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
self.autoderef(DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
|
||||
self.autoderef(DUMMY_SP, expr_ty).silence_errors().nth(1).and_then(|(deref_ty, _)| {
|
||||
self.infcx
|
||||
.type_implements_trait(
|
||||
self.tcx.lang_items().deref_mut_trait()?,
|
||||
|
|
|
@ -2864,13 +2864,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(expr_t, "")
|
||||
};
|
||||
for (found_fields, args) in
|
||||
self.get_field_candidates_considering_privacy(span, ty, mod_id, id)
|
||||
self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, id)
|
||||
{
|
||||
let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>();
|
||||
let mut candidate_fields: Vec<_> = found_fields
|
||||
.into_iter()
|
||||
.filter_map(|candidate_field| {
|
||||
self.check_for_nested_field_satisfying(
|
||||
self.check_for_nested_field_satisfying_condition_for_diag(
|
||||
span,
|
||||
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
|
||||
candidate_field,
|
||||
|
@ -2933,7 +2933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.with_span_label(field.span, "private field")
|
||||
}
|
||||
|
||||
pub(crate) fn get_field_candidates_considering_privacy(
|
||||
pub(crate) fn get_field_candidates_considering_privacy_for_diag(
|
||||
&self,
|
||||
span: Span,
|
||||
base_ty: Ty<'tcx>,
|
||||
|
@ -2942,7 +2942,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> {
|
||||
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
|
||||
|
||||
self.autoderef(span, base_ty)
|
||||
let mut autoderef = self.autoderef(span, base_ty).silence_errors();
|
||||
let deref_chain: Vec<_> = autoderef.by_ref().collect();
|
||||
|
||||
// Don't probe if we hit the recursion limit, since it may result in
|
||||
// quadratic blowup if we then try to further deref the results of this
|
||||
// function. This is a best-effort method, after all.
|
||||
if autoderef.reached_recursion_limit() {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
deref_chain
|
||||
.into_iter()
|
||||
.filter_map(move |(base_t, _)| {
|
||||
match base_t.kind() {
|
||||
ty::Adt(base_def, args) if !base_def.is_enum() => {
|
||||
|
@ -2975,7 +2986,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
/// This method is called after we have encountered a missing field error to recursively
|
||||
/// search for the field
|
||||
pub(crate) fn check_for_nested_field_satisfying(
|
||||
pub(crate) fn check_for_nested_field_satisfying_condition_for_diag(
|
||||
&self,
|
||||
span: Span,
|
||||
matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
|
||||
|
@ -3000,20 +3011,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if matches(candidate_field, field_ty) {
|
||||
return Some(field_path);
|
||||
} else {
|
||||
for (nested_fields, subst) in
|
||||
self.get_field_candidates_considering_privacy(span, field_ty, mod_id, hir_id)
|
||||
for (nested_fields, subst) in self
|
||||
.get_field_candidates_considering_privacy_for_diag(
|
||||
span, field_ty, mod_id, hir_id,
|
||||
)
|
||||
{
|
||||
// recursively search fields of `candidate_field` if it's a ty::Adt
|
||||
for field in nested_fields {
|
||||
if let Some(field_path) = self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
matches,
|
||||
field,
|
||||
subst,
|
||||
field_path.clone(),
|
||||
mod_id,
|
||||
hir_id,
|
||||
) {
|
||||
if let Some(field_path) = self
|
||||
.check_for_nested_field_satisfying_condition_for_diag(
|
||||
span,
|
||||
matches,
|
||||
field,
|
||||
subst,
|
||||
field_path.clone(),
|
||||
mod_id,
|
||||
hir_id,
|
||||
)
|
||||
{
|
||||
return Some(field_path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2619,9 +2619,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
is_method: bool,
|
||||
) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> {
|
||||
let fn_node = self.tcx.hir().get_if_local(def_id)?;
|
||||
let fn_decl = fn_node.fn_decl()?;
|
||||
|
||||
let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
|
||||
.fn_decl()?
|
||||
let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_decl
|
||||
.inputs
|
||||
.into_iter()
|
||||
.skip(if is_method { 1 } else { 0 })
|
||||
|
@ -2642,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let params: Vec<&hir::Param<'_>> = self
|
||||
let mut params: Vec<&hir::Param<'_>> = self
|
||||
.tcx
|
||||
.hir()
|
||||
.body(fn_node.body_id()?)
|
||||
|
@ -2651,7 +2651,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.skip(if is_method { 1 } else { 0 })
|
||||
.collect();
|
||||
|
||||
Some(generic_params.into_iter().zip_eq(params).collect())
|
||||
// The surrounding code expects variadic functions to not have a parameter representing
|
||||
// the "..." parameter. This is already true of the FnDecl but not of the body params, so
|
||||
// we drop it if it exists.
|
||||
|
||||
if fn_decl.c_variadic {
|
||||
params.pop();
|
||||
}
|
||||
|
||||
debug_assert_eq!(params.len(), generic_params.len());
|
||||
Some(generic_params.into_iter().zip(params).collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// If our autoderef loop had reached the recursion limit,
|
||||
// report an overflow error, but continue going on with
|
||||
// the truncated autoderef list.
|
||||
if steps.reached_recursion_limit {
|
||||
if steps.reached_recursion_limit && !is_suggestion.0 {
|
||||
self.probe(|_| {
|
||||
let ty = &steps
|
||||
.steps
|
||||
|
|
|
@ -62,14 +62,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// It might seem that we can use `predicate_must_hold_modulo_regions`,
|
||||
// but since a Dummy binder is used to fill in the FnOnce trait's arguments,
|
||||
// type resolution always gives a "maybe" here.
|
||||
if self.autoderef(span, ty).any(|(ty, _)| {
|
||||
if self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
|
||||
info!("check deref {:?} error", ty);
|
||||
matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
|
||||
}) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.autoderef(span, ty).any(|(ty, _)| {
|
||||
self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
|
||||
info!("check deref {:?} impl FnOnce", ty);
|
||||
self.probe(|_| {
|
||||
let trait_ref =
|
||||
|
@ -90,7 +90,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
||||
self.autoderef(span, ty)
|
||||
.silence_errors()
|
||||
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
||||
}
|
||||
|
||||
fn impl_into_iterator_should_be_iterator(
|
||||
|
@ -672,7 +674,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut ty_str_reported = ty_str.clone();
|
||||
if let ty::Adt(_, generics) = rcvr_ty.kind() {
|
||||
if generics.len() > 0 {
|
||||
let mut autoderef = self.autoderef(span, rcvr_ty);
|
||||
let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
|
||||
let candidate_found = autoderef.any(|(ty, _)| {
|
||||
if let ty::Adt(adt_def, _) = ty.kind() {
|
||||
self.tcx
|
||||
|
@ -2237,6 +2239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity();
|
||||
let target_ty = self
|
||||
.autoderef(sugg_span, rcvr_ty)
|
||||
.silence_errors()
|
||||
.find(|(rcvr_ty, _)| {
|
||||
DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty)
|
||||
})
|
||||
|
@ -2352,17 +2355,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err: &mut Diag<'_>,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
|
||||
ty::Adt(def, args) if !def.is_enum() => {
|
||||
let variant = &def.non_enum_variant();
|
||||
tcx.find_field_index(item_name, variant).map(|index| {
|
||||
let field = &variant.fields[index];
|
||||
let field_ty = field.ty(tcx, args);
|
||||
(field, field_ty)
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
let field_receiver =
|
||||
self.autoderef(span, rcvr_ty).silence_errors().find_map(|(ty, _)| match ty.kind() {
|
||||
ty::Adt(def, args) if !def.is_enum() => {
|
||||
let variant = &def.non_enum_variant();
|
||||
tcx.find_field_index(item_name, variant).map(|index| {
|
||||
let field = &variant.fields[index];
|
||||
let field_ty = field.ty(tcx, args);
|
||||
(field, field_ty)
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
if let Some((field, field_ty)) = field_receiver {
|
||||
let scope = tcx.parent_module_from_def_id(self.body_id);
|
||||
let is_accessible = field.vis.is_accessible_from(scope, tcx);
|
||||
|
@ -2675,9 +2679,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) {
|
||||
if let SelfSource::MethodCall(expr) = source {
|
||||
let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
|
||||
for (fields, args) in
|
||||
self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id)
|
||||
{
|
||||
for (fields, args) in self.get_field_candidates_considering_privacy_for_diag(
|
||||
span,
|
||||
actual,
|
||||
mod_id,
|
||||
expr.hir_id,
|
||||
) {
|
||||
let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
|
||||
|
||||
let lang_items = self.tcx.lang_items();
|
||||
|
@ -2693,7 +2700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut candidate_fields: Vec<_> = fields
|
||||
.into_iter()
|
||||
.filter_map(|candidate_field| {
|
||||
self.check_for_nested_field_satisfying(
|
||||
self.check_for_nested_field_satisfying_condition_for_diag(
|
||||
span,
|
||||
&|_, field_ty| {
|
||||
self.lookup_probe_for_diagnostic(
|
||||
|
@ -3195,7 +3202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let SelfSource::QPath(ty) = self_source else {
|
||||
return;
|
||||
};
|
||||
for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).skip(1) {
|
||||
for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).silence_errors().skip(1) {
|
||||
if let Ok(pick) = self.probe_for_name(
|
||||
Mode::Path,
|
||||
item_name,
|
||||
|
@ -4221,7 +4228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return is_local(rcvr_ty);
|
||||
}
|
||||
|
||||
self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
|
||||
self.autoderef(span, rcvr_ty).silence_errors().any(|(ty, _)| is_local(ty))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2533,6 +2533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.help("the semantics of slice patterns changed recently; see issue #62254");
|
||||
} else if self
|
||||
.autoderef(span, expected_ty)
|
||||
.silence_errors()
|
||||
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
||||
&& let Some(span) = ti.span
|
||||
&& let Some(_) = ti.origin_expr
|
||||
|
|
|
@ -20,7 +20,7 @@ pub struct IndexSlice<I: Idx, T> {
|
|||
|
||||
impl<I: Idx, T> IndexSlice<I, T> {
|
||||
#[inline]
|
||||
pub const fn empty() -> &'static Self {
|
||||
pub const fn empty<'a>() -> &'a Self {
|
||||
Self::from_raw(&[])
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,10 @@ fn main() {
|
|||
let mut cmd = Command::new(&llvm_config);
|
||||
cmd.arg(llvm_link_arg).arg("--libs");
|
||||
|
||||
if !is_crossed {
|
||||
// Don't link system libs if cross-compiling unless targetting Windows.
|
||||
// On Windows system DLLs aren't linked directly, instead import libraries are used.
|
||||
// These import libraries are independent of the host.
|
||||
if !is_crossed || target.contains("windows") {
|
||||
cmd.arg("--system-libs");
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ pub mod locator;
|
|||
pub use creader::{load_symbol_from_dylib, DylibError};
|
||||
pub use fs::{emit_wrapper_file, METADATA_FILENAME};
|
||||
pub use native_libs::{
|
||||
find_native_static_library, try_find_native_static_library, walk_native_lib_search_dirs,
|
||||
find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
|
||||
walk_native_lib_search_dirs,
|
||||
};
|
||||
pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};
|
||||
|
||||
|
|
|
@ -109,6 +109,44 @@ pub fn try_find_native_static_library(
|
|||
.break_value()
|
||||
}
|
||||
|
||||
pub fn try_find_native_dynamic_library(
|
||||
sess: &Session,
|
||||
name: &str,
|
||||
verbatim: bool,
|
||||
) -> Option<PathBuf> {
|
||||
let formats = if verbatim {
|
||||
vec![("".into(), "".into())]
|
||||
} else {
|
||||
// While the official naming convention for MSVC import libraries
|
||||
// is foo.lib...
|
||||
let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone());
|
||||
// ... Meson follows the libfoo.dll.a convention to
|
||||
// disambiguate .a for static libraries
|
||||
let meson = ("lib".into(), ".dll.a".into());
|
||||
// and MinGW uses .a altogether
|
||||
let mingw = ("lib".into(), ".a".into());
|
||||
vec![os, meson, mingw]
|
||||
};
|
||||
|
||||
walk_native_lib_search_dirs(
|
||||
sess,
|
||||
LinkSelfContainedComponents::empty(),
|
||||
None,
|
||||
|dir, is_framework| {
|
||||
if !is_framework {
|
||||
for (prefix, suffix) in &formats {
|
||||
let test = dir.join(format!("{prefix}{name}{suffix}"));
|
||||
if test.exists() {
|
||||
return ControlFlow::Break(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
},
|
||||
)
|
||||
.break_value()
|
||||
}
|
||||
|
||||
pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
|
||||
try_find_native_static_library(sess, name, verbatim)
|
||||
.unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim)))
|
||||
|
|
|
@ -255,7 +255,9 @@ impl<'tcx> Generics {
|
|||
let param = self.param_at(param.index as usize, tcx);
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => param,
|
||||
_ => bug!("expected lifetime parameter, but found another generic parameter"),
|
||||
_ => {
|
||||
bug!("expected lifetime parameter, but found another generic parameter: {param:#?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,7 +266,7 @@ impl<'tcx> Generics {
|
|||
let param = self.param_at(param.index as usize, tcx);
|
||||
match param.kind {
|
||||
GenericParamDefKind::Type { .. } => param,
|
||||
_ => bug!("expected type parameter, but found another generic parameter"),
|
||||
_ => bug!("expected type parameter, but found another generic parameter: {param:#?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,7 +275,7 @@ impl<'tcx> Generics {
|
|||
let param = self.param_at(param.index as usize, tcx);
|
||||
match param.kind {
|
||||
GenericParamDefKind::Const { .. } => param,
|
||||
_ => bug!("expected const parameter, but found another generic parameter"),
|
||||
_ => bug!("expected const parameter, but found another generic parameter: {param:#?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::borrow::Cow;
|
||||
use std::num::NonZero;
|
||||
use std::ops::Bound;
|
||||
use std::{cmp, fmt};
|
||||
|
@ -286,20 +285,14 @@ impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LayoutCx<'tcx, C> {
|
||||
pub tcx: C,
|
||||
pub struct LayoutCx<'tcx> {
|
||||
pub calc: LayoutCalculator<TyCtxt<'tcx>>,
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
type TargetDataLayoutRef = &'tcx TargetDataLayout;
|
||||
|
||||
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
|
||||
self.tcx.dcx().delayed_bug(txt);
|
||||
}
|
||||
|
||||
fn current_data_layout(&self) -> Self::TargetDataLayoutRef {
|
||||
&self.tcx.data_layout
|
||||
impl<'tcx> LayoutCx<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
Self { calc: LayoutCalculator::new(tcx), param_env }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,33 +561,33 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
|
||||
impl<'tcx> HasParamEnv<'tcx> for LayoutCx<'tcx> {
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.param_env
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
|
||||
impl<'tcx> HasDataLayout for LayoutCx<'tcx> {
|
||||
fn data_layout(&self) -> &TargetDataLayout {
|
||||
self.tcx.data_layout()
|
||||
self.calc.cx.data_layout()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
|
||||
impl<'tcx> HasTargetSpec for LayoutCx<'tcx> {
|
||||
fn target_spec(&self) -> &Target {
|
||||
self.tcx.target_spec()
|
||||
self.calc.cx.target_spec()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: HasWasmCAbiOpt> HasWasmCAbiOpt for LayoutCx<'tcx, T> {
|
||||
impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.tcx.wasm_c_abi_opt()
|
||||
self.calc.cx.wasm_c_abi_opt()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
|
||||
impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx.tcx()
|
||||
self.calc.cx
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -685,7 +678,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
|
|||
|
||||
impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
|
||||
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
|
||||
type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
|
||||
|
||||
#[inline]
|
||||
|
@ -695,26 +688,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
_: Span,
|
||||
_: Ty<'tcx>,
|
||||
) -> &'tcx LayoutError<'tcx> {
|
||||
self.tcx.arena.alloc(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
|
||||
type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
|
||||
|
||||
#[inline]
|
||||
fn layout_tcx_at_span(&self) -> Span {
|
||||
self.tcx.span
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn handle_layout_err(
|
||||
&self,
|
||||
err: LayoutError<'tcx>,
|
||||
_: Span,
|
||||
_: Ty<'tcx>,
|
||||
) -> &'tcx LayoutError<'tcx> {
|
||||
self.tcx.arena.alloc(err)
|
||||
self.tcx().arena.alloc(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1342,7 +1316,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
where
|
||||
I: Iterator<Item = (VariantIdx, FieldIdx)>,
|
||||
{
|
||||
let cx = LayoutCx { tcx: self, param_env };
|
||||
let cx = LayoutCx::new(self, param_env);
|
||||
let mut offset = Size::ZERO;
|
||||
|
||||
for (variant, field) in indices {
|
||||
|
|
|
@ -571,7 +571,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Returns `true` if `def_id` refers to a definition that does not have its own
|
||||
/// type-checking context, i.e. closure, coroutine or inline const.
|
||||
pub fn is_typeck_child(self, def_id: DefId) -> bool {
|
||||
matches!(self.def_kind(def_id), DefKind::Closure | DefKind::InlineConst)
|
||||
matches!(
|
||||
self.def_kind(def_id),
|
||||
DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
|
||||
|
|
|
@ -1070,19 +1070,26 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
|
|||
let locals = local_decls_for_sig(&sig, span);
|
||||
|
||||
let mut fields = vec![];
|
||||
|
||||
// Move all of the closure args.
|
||||
for idx in 1..sig.inputs().len() {
|
||||
fields.push(Operand::Move(Local::from_usize(idx + 1).into()));
|
||||
}
|
||||
|
||||
for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
|
||||
if receiver_by_ref {
|
||||
// The only situation where it's possible is when we capture immuatable references,
|
||||
// since those don't need to be reborrowed with the closure's env lifetime. Since
|
||||
// references are always `Copy`, just emit a copy.
|
||||
assert_matches!(
|
||||
ty.kind(),
|
||||
ty::Ref(_, _, hir::Mutability::Not),
|
||||
"field should be captured by immutable ref if we have an `Fn` instance"
|
||||
);
|
||||
if !matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) {
|
||||
// This copy is only sound if it's a `&T`. This may be
|
||||
// reachable e.g. when eagerly computing the `Fn` instance
|
||||
// of an async closure that doesn't borrowck.
|
||||
tcx.dcx().delayed_bug(format!(
|
||||
"field should be captured by immutable ref if we have \
|
||||
an `Fn` instance, but it was: {ty}"
|
||||
));
|
||||
}
|
||||
fields.push(Operand::Copy(tcx.mk_place_field(
|
||||
self_local,
|
||||
FieldIdx::from_usize(idx),
|
||||
|
|
|
@ -128,7 +128,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
|
|||
}
|
||||
|
||||
Err(layout_error) => {
|
||||
tcx.dcx().emit_fatal(Spanned { node: layout_error.into_diagnostic(), span });
|
||||
tcx.dcx().emit_err(Spanned { node: layout_error.into_diagnostic(), span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -402,6 +402,8 @@ pub(crate) enum PathSource<'a> {
|
|||
TraitItem(Namespace),
|
||||
// Paths in delegation item
|
||||
Delegation,
|
||||
/// An arg in a `use<'a, N>` precise-capturing bound.
|
||||
PreciseCapturingArg(Namespace),
|
||||
}
|
||||
|
||||
impl<'a> PathSource<'a> {
|
||||
|
@ -413,6 +415,7 @@ impl<'a> PathSource<'a> {
|
|||
| PathSource::TupleStruct(..)
|
||||
| PathSource::Delegation => ValueNS,
|
||||
PathSource::TraitItem(ns) => ns,
|
||||
PathSource::PreciseCapturingArg(ns) => ns,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,7 +426,10 @@ impl<'a> PathSource<'a> {
|
|||
| PathSource::Pat
|
||||
| PathSource::Struct
|
||||
| PathSource::TupleStruct(..) => true,
|
||||
PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Delegation => false,
|
||||
PathSource::Trait(_)
|
||||
| PathSource::TraitItem(..)
|
||||
| PathSource::Delegation
|
||||
| PathSource::PreciseCapturingArg(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,6 +472,7 @@ impl<'a> PathSource<'a> {
|
|||
_ => "value",
|
||||
},
|
||||
PathSource::Delegation => "function",
|
||||
PathSource::PreciseCapturingArg(..) => "type or const parameter",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,6 +541,15 @@ impl<'a> PathSource<'a> {
|
|||
_ => false,
|
||||
},
|
||||
PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
|
||||
PathSource::PreciseCapturingArg(ValueNS) => {
|
||||
matches!(res, Res::Def(DefKind::ConstParam, _))
|
||||
}
|
||||
// We allow `SelfTyAlias` here so we can give a more descriptive error later.
|
||||
PathSource::PreciseCapturingArg(TypeNS) => matches!(
|
||||
res,
|
||||
Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }
|
||||
),
|
||||
PathSource::PreciseCapturingArg(MacroNS) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,6 +567,8 @@ impl<'a> PathSource<'a> {
|
|||
(PathSource::Pat | PathSource::TupleStruct(..), false) => E0531,
|
||||
(PathSource::TraitItem(..), true) => E0575,
|
||||
(PathSource::TraitItem(..), false) => E0576,
|
||||
(PathSource::PreciseCapturingArg(..), true) => E0799,
|
||||
(PathSource::PreciseCapturingArg(..), false) => E0800,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1077,9 +1095,19 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
};
|
||||
// Like `Ty::Param`, we try resolving this as both a const and a type.
|
||||
if !check_ns(TypeNS) && check_ns(ValueNS) {
|
||||
self.smart_resolve_path(*id, &None, path, PathSource::Expr(None));
|
||||
self.smart_resolve_path(
|
||||
*id,
|
||||
&None,
|
||||
path,
|
||||
PathSource::PreciseCapturingArg(ValueNS),
|
||||
);
|
||||
} else {
|
||||
self.smart_resolve_path(*id, &None, path, PathSource::Type);
|
||||
self.smart_resolve_path(
|
||||
*id,
|
||||
&None,
|
||||
path,
|
||||
PathSource::PreciseCapturingArg(TypeNS),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1889,7 +1917,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
);
|
||||
|
||||
let inferred = match source {
|
||||
PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => false,
|
||||
PathSource::Trait(..)
|
||||
| PathSource::TraitItem(..)
|
||||
| PathSource::Type
|
||||
| PathSource::PreciseCapturingArg(..) => false,
|
||||
PathSource::Expr(..)
|
||||
| PathSource::Pat
|
||||
| PathSource::Struct
|
||||
|
@ -3982,7 +4013,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
))
|
||||
} else if res.is_none()
|
||||
&& let PathSource::Type | PathSource::Expr(_) = source
|
||||
&& let PathSource::Type
|
||||
| PathSource::Expr(_)
|
||||
| PathSource::PreciseCapturingArg(..) = source
|
||||
{
|
||||
this.suggest_adding_generic_parameter(path, source)
|
||||
} else {
|
||||
|
|
|
@ -2068,33 +2068,34 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
) {
|
||||
let res = binding.res();
|
||||
if filter_fn(res) {
|
||||
let def_id = res.def_id();
|
||||
let has_self = match def_id.as_local() {
|
||||
Some(def_id) => {
|
||||
self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self)
|
||||
}
|
||||
None => self
|
||||
.r
|
||||
.tcx
|
||||
.fn_arg_names(def_id)
|
||||
.first()
|
||||
.is_some_and(|ident| ident.name == kw::SelfLower),
|
||||
};
|
||||
if has_self {
|
||||
return Some(AssocSuggestion::MethodWithSelf { called });
|
||||
} else {
|
||||
match res {
|
||||
Res::Def(DefKind::AssocFn, _) => {
|
||||
match res {
|
||||
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => {
|
||||
let has_self = match def_id.as_local() {
|
||||
Some(def_id) => self
|
||||
.r
|
||||
.delegation_fn_sigs
|
||||
.get(&def_id)
|
||||
.map_or(false, |sig| sig.has_self),
|
||||
None => self
|
||||
.r
|
||||
.tcx
|
||||
.fn_arg_names(def_id)
|
||||
.first()
|
||||
.is_some_and(|ident| ident.name == kw::SelfLower),
|
||||
};
|
||||
if has_self {
|
||||
return Some(AssocSuggestion::MethodWithSelf { called });
|
||||
} else {
|
||||
return Some(AssocSuggestion::AssocFn { called });
|
||||
}
|
||||
Res::Def(DefKind::AssocConst, _) => {
|
||||
return Some(AssocSuggestion::AssocConst);
|
||||
}
|
||||
Res::Def(DefKind::AssocTy, _) => {
|
||||
return Some(AssocSuggestion::AssocType);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Res::Def(DefKind::AssocConst, _) => {
|
||||
return Some(AssocSuggestion::AssocConst);
|
||||
}
|
||||
Res::Def(DefKind::AssocTy, _) => {
|
||||
return Some(AssocSuggestion::AssocType);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2538,8 +2539,13 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
|
||||
let (msg, sugg) = match source {
|
||||
PathSource::Type => ("you might be missing a type parameter", ident),
|
||||
PathSource::Expr(_) => ("you might be missing a const parameter", format!("const {ident}: /* Type */")),
|
||||
PathSource::Type | PathSource::PreciseCapturingArg(TypeNS) => {
|
||||
("you might be missing a type parameter", ident)
|
||||
}
|
||||
PathSource::Expr(_) | PathSource::PreciseCapturingArg(ValueNS) => (
|
||||
"you might be missing a const parameter",
|
||||
format!("const {ident}: /* Type */"),
|
||||
),
|
||||
_ => return None,
|
||||
};
|
||||
let (span, sugg) = if let [.., param] = &generics.params[..] {
|
||||
|
|
|
@ -63,8 +63,8 @@ pub mod rustc {
|
|||
use std::fmt::{self, Write};
|
||||
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_target::abi::Layout;
|
||||
|
||||
/// A reference in the layout.
|
||||
|
@ -124,11 +124,11 @@ pub mod rustc {
|
|||
}
|
||||
|
||||
pub(crate) fn layout_of<'tcx>(
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
let ty = cx.tcx.erase_regions(ty);
|
||||
let ty = cx.tcx().erase_regions(ty);
|
||||
cx.layout_of(ty).map(|tl| tl.layout)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,7 +204,7 @@ pub(crate) mod rustc {
|
|||
}
|
||||
|
||||
impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
|
||||
pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, Err> {
|
||||
pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
|
||||
use rustc_target::abi::HasDataLayout;
|
||||
let layout = layout_of(cx, ty)?;
|
||||
|
||||
|
@ -212,7 +212,7 @@ pub(crate) mod rustc {
|
|||
return Err(Err::TypeError(e));
|
||||
}
|
||||
|
||||
let target = cx.tcx.data_layout();
|
||||
let target = cx.data_layout();
|
||||
let pointer_size = target.pointer_size;
|
||||
|
||||
match ty.kind() {
|
||||
|
@ -274,7 +274,7 @@ pub(crate) mod rustc {
|
|||
fn from_tuple(
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
members: &'tcx List<Ty<'tcx>>,
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
) -> Result<Self, Err> {
|
||||
match &layout.fields {
|
||||
FieldsShape::Primitive => {
|
||||
|
@ -299,7 +299,7 @@ pub(crate) mod rustc {
|
|||
fn from_struct(
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
def: AdtDef<'tcx>,
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
) -> Result<Self, Err> {
|
||||
assert!(def.is_struct());
|
||||
let def = Def::Adt(def);
|
||||
|
@ -314,13 +314,13 @@ pub(crate) mod rustc {
|
|||
fn from_enum(
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
def: AdtDef<'tcx>,
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
) -> Result<Self, Err> {
|
||||
assert!(def.is_enum());
|
||||
|
||||
// Computes the variant of a given index.
|
||||
let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| {
|
||||
let tag = cx.tcx.tag_for_variant((cx.tcx.erase_regions(ty), index));
|
||||
let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index));
|
||||
let variant_def = Def::Variant(def.variant(index));
|
||||
let variant_layout = ty_variant(cx, (ty, layout), index);
|
||||
Self::from_variant(
|
||||
|
@ -389,7 +389,7 @@ pub(crate) mod rustc {
|
|||
tag: Option<(ScalarInt, VariantIdx, TagEncoding<VariantIdx>)>,
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
total_size: Size,
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
) -> Result<Self, Err> {
|
||||
// This constructor does not support non-`FieldsShape::Arbitrary`
|
||||
// layouts.
|
||||
|
@ -417,7 +417,7 @@ pub(crate) mod rustc {
|
|||
}
|
||||
}
|
||||
}
|
||||
struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx));
|
||||
struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx()));
|
||||
}
|
||||
|
||||
// Append the fields, in memory order, to the layout.
|
||||
|
@ -470,7 +470,7 @@ pub(crate) mod rustc {
|
|||
fn from_union(
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
def: AdtDef<'tcx>,
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
) -> Result<Self, Err> {
|
||||
assert!(def.is_union());
|
||||
|
||||
|
@ -500,7 +500,7 @@ pub(crate) mod rustc {
|
|||
}
|
||||
|
||||
fn ty_field<'tcx>(
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
i: FieldIdx,
|
||||
) -> Ty<'tcx> {
|
||||
|
@ -509,12 +509,12 @@ pub(crate) mod rustc {
|
|||
match layout.variants {
|
||||
Variants::Single { index } => {
|
||||
let field = &def.variant(index).fields[i];
|
||||
field.ty(cx.tcx, args)
|
||||
field.ty(cx.tcx(), args)
|
||||
}
|
||||
// Discriminant field for enums (where applicable).
|
||||
Variants::Multiple { tag, .. } => {
|
||||
assert_eq!(i.as_usize(), 0);
|
||||
ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx)
|
||||
ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -527,11 +527,11 @@ pub(crate) mod rustc {
|
|||
}
|
||||
|
||||
fn ty_variant<'tcx>(
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
||||
i: VariantIdx,
|
||||
) -> Layout<'tcx> {
|
||||
let ty = cx.tcx.erase_regions(ty);
|
||||
let ty = cx.tcx().erase_regions(ty);
|
||||
TyAndLayout { ty, layout }.for_variant(&cx, i).layout
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ mod rustc {
|
|||
pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
|
||||
let Self { src, dst, assume, context } = self;
|
||||
|
||||
let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() };
|
||||
let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all());
|
||||
|
||||
// Convert `src` and `dst` from their rustc representations, to `Tree`-based
|
||||
// representations.
|
||||
|
|
|
@ -331,7 +331,7 @@ fn fn_abi_of_fn_ptr<'tcx>(
|
|||
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
|
||||
let (param_env, (sig, extra_args)) = query.into_parts();
|
||||
|
||||
let cx = LayoutCx { tcx, param_env };
|
||||
let cx = LayoutCx::new(tcx, param_env);
|
||||
fn_abi_new_uncached(&cx, sig, extra_args, None, None, false)
|
||||
}
|
||||
|
||||
|
@ -347,7 +347,7 @@ fn fn_abi_of_instance<'tcx>(
|
|||
instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty());
|
||||
|
||||
fn_abi_new_uncached(
|
||||
&LayoutCx { tcx, param_env },
|
||||
&LayoutCx::new(tcx, param_env),
|
||||
sig,
|
||||
extra_args,
|
||||
caller_location,
|
||||
|
@ -358,7 +358,7 @@ fn fn_abi_of_instance<'tcx>(
|
|||
|
||||
// Handle safe Rust thin and fat pointers.
|
||||
fn adjust_for_rust_scalar<'tcx>(
|
||||
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: LayoutCx<'tcx>,
|
||||
attrs: &mut ArgAttributes,
|
||||
scalar: Scalar,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
|
@ -386,12 +386,14 @@ fn adjust_for_rust_scalar<'tcx>(
|
|||
attrs.set(ArgAttribute::NonNull);
|
||||
}
|
||||
|
||||
let tcx = cx.tcx();
|
||||
|
||||
if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
|
||||
let kind = if let Some(kind) = pointee.safe {
|
||||
Some(kind)
|
||||
} else if let Some(pointee) = drop_target_pointee {
|
||||
// The argument to `drop_in_place` is semantically equivalent to a mutable reference.
|
||||
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(cx.tcx, cx.param_env()) })
|
||||
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.param_env()) })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -415,12 +417,12 @@ fn adjust_for_rust_scalar<'tcx>(
|
|||
// The aliasing rules for `Box<T>` are still not decided, but currently we emit
|
||||
// `noalias` for it. This can be turned off using an unstable flag.
|
||||
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
|
||||
let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias;
|
||||
let noalias_for_box = tcx.sess.opts.unstable_opts.box_noalias;
|
||||
|
||||
// LLVM prior to version 12 had known miscompiles in the presence of noalias attributes
|
||||
// (see #54878), so it was conditionally disabled, but we don't support earlier
|
||||
// versions at all anymore. We still support turning it off using -Zmutable-noalias.
|
||||
let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias;
|
||||
let noalias_mut_ref = tcx.sess.opts.unstable_opts.mutable_noalias;
|
||||
|
||||
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
|
||||
// `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
|
||||
|
@ -448,16 +450,17 @@ fn adjust_for_rust_scalar<'tcx>(
|
|||
|
||||
/// Ensure that the ABI makes basic sense.
|
||||
fn fn_abi_sanity_check<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
spec_abi: SpecAbi,
|
||||
) {
|
||||
fn fn_arg_sanity_check<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
spec_abi: SpecAbi,
|
||||
arg: &ArgAbi<'tcx, Ty<'tcx>>,
|
||||
) {
|
||||
let tcx = cx.tcx();
|
||||
match &arg.mode {
|
||||
PassMode::Ignore => {}
|
||||
PassMode::Direct(_) => {
|
||||
|
@ -484,7 +487,7 @@ fn fn_abi_sanity_check<'tcx>(
|
|||
// It needs to switch to something else before stabilization can happen.
|
||||
// (See issue: https://github.com/rust-lang/rust/issues/117271)
|
||||
assert!(
|
||||
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64")
|
||||
matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64")
|
||||
|| matches!(spec_abi, SpecAbi::PtxKernel | SpecAbi::Unadjusted),
|
||||
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\
|
||||
Problematic type: {:#?}",
|
||||
|
@ -516,7 +519,7 @@ fn fn_abi_sanity_check<'tcx>(
|
|||
// With metadata. Must be unsized and not on the stack.
|
||||
assert!(arg.layout.is_unsized() && !on_stack);
|
||||
// Also, must not be `extern` type.
|
||||
let tail = cx.tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
|
||||
let tail = tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
|
||||
if matches!(tail.kind(), ty::Foreign(..)) {
|
||||
// These types do not have metadata, so having `meta_attrs` is bogus.
|
||||
// Conceptually, unsized arguments must be copied around, which requires dynamically
|
||||
|
@ -538,7 +541,7 @@ fn fn_abi_sanity_check<'tcx>(
|
|||
// arguments of this method, into a separate `struct`.
|
||||
#[tracing::instrument(level = "debug", skip(cx, caller_location, fn_def_id, force_thin_self_ptr))]
|
||||
fn fn_abi_new_uncached<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
extra_args: &[Ty<'tcx>],
|
||||
caller_location: Option<Ty<'tcx>>,
|
||||
|
@ -546,7 +549,8 @@ fn fn_abi_new_uncached<'tcx>(
|
|||
// FIXME(eddyb) replace this with something typed, like an `enum`.
|
||||
force_thin_self_ptr: bool,
|
||||
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
|
||||
let sig = cx.tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
|
||||
let tcx = cx.tcx();
|
||||
let sig = tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
|
||||
|
||||
let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
|
||||
|
||||
|
@ -576,7 +580,7 @@ fn fn_abi_new_uncached<'tcx>(
|
|||
};
|
||||
|
||||
let is_drop_in_place =
|
||||
fn_def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::DropInPlace));
|
||||
fn_def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::DropInPlace));
|
||||
|
||||
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, &'tcx FnAbiError<'tcx>> {
|
||||
let span = tracing::debug_span!("arg_of");
|
||||
|
@ -588,8 +592,7 @@ fn fn_abi_new_uncached<'tcx>(
|
|||
_ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
|
||||
});
|
||||
|
||||
let layout =
|
||||
cx.layout_of(ty).map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::Layout(*err)))?;
|
||||
let layout = cx.layout_of(ty).map_err(|err| &*tcx.arena.alloc(FnAbiError::Layout(*err)))?;
|
||||
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
|
||||
// Don't pass the vtable, it's not an argument of the virtual fn.
|
||||
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
|
||||
|
@ -638,12 +641,12 @@ fn fn_abi_new_uncached<'tcx>(
|
|||
fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?;
|
||||
debug!("fn_abi_new_uncached = {:?}", fn_abi);
|
||||
fn_abi_sanity_check(cx, &fn_abi, sig.abi);
|
||||
Ok(cx.tcx.arena.alloc(fn_abi))
|
||||
Ok(tcx.arena.alloc(fn_abi))
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(cx))]
|
||||
fn fn_abi_adjust_for_abi<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
|
||||
abi: SpecAbi,
|
||||
fn_def_id: Option<DefId>,
|
||||
|
@ -670,17 +673,18 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let tcx = cx.tcx();
|
||||
|
||||
if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic {
|
||||
// Look up the deduced parameter attributes for this function, if we have its def ID and
|
||||
// we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
|
||||
// as appropriate.
|
||||
let deduced_param_attrs = if cx.tcx.sess.opts.optimize != OptLevel::No
|
||||
&& cx.tcx.sess.opts.incremental.is_none()
|
||||
{
|
||||
fn_def_id.map(|fn_def_id| cx.tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
let deduced_param_attrs =
|
||||
if tcx.sess.opts.optimize != OptLevel::No && tcx.sess.opts.incremental.is_none() {
|
||||
fn_def_id.map(|fn_def_id| tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
|
||||
let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
|
||||
if arg.is_ignore() {
|
||||
|
@ -689,7 +693,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
|||
|
||||
// Avoid returning floats in x87 registers on x86 as loading and storing from x87
|
||||
// registers will quiet signalling NaNs.
|
||||
if cx.tcx.sess.target.arch == "x86"
|
||||
if tcx.sess.target.arch == "x86"
|
||||
&& arg_idx.is_none()
|
||||
// Intrinsics themselves are not actual "real" functions, so theres no need to
|
||||
// change their ABIs.
|
||||
|
@ -744,7 +748,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
|||
// that's how we connect up to LLVM and it's unstable
|
||||
// anyway, we control all calls to it in libstd.
|
||||
Abi::Vector { .. }
|
||||
if abi != SpecAbi::RustIntrinsic && cx.tcx.sess.target.simd_types_indirect =>
|
||||
if abi != SpecAbi::RustIntrinsic && tcx.sess.target.simd_types_indirect =>
|
||||
{
|
||||
arg.make_indirect();
|
||||
return;
|
||||
|
@ -793,7 +797,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
|||
} else {
|
||||
fn_abi
|
||||
.adjust_for_foreign_abi(cx, abi)
|
||||
.map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?;
|
||||
.map_err(|err| &*tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -9,12 +9,11 @@ use rustc_middle::bug;
|
|||
use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::layout::{
|
||||
FloatExt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
|
||||
FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
|
||||
};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, CoroutineArgsExt, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt,
|
||||
TypeVisitableExt,
|
||||
self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt,
|
||||
};
|
||||
use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
|
||||
use rustc_span::sym;
|
||||
|
@ -63,14 +62,14 @@ fn layout_of<'tcx>(
|
|||
return tcx.layout_of(param_env.and(ty));
|
||||
}
|
||||
|
||||
let cx = LayoutCx { tcx, param_env };
|
||||
let cx = LayoutCx::new(tcx, param_env);
|
||||
|
||||
let layout = layout_of_uncached(&cx, ty)?;
|
||||
let layout = TyAndLayout { ty, layout };
|
||||
|
||||
// If we are running with `-Zprint-type-sizes`, maybe record layouts
|
||||
// for dumping later.
|
||||
if cx.tcx.sess.opts.unstable_opts.print_type_sizes {
|
||||
if cx.tcx().sess.opts.unstable_opts.print_type_sizes {
|
||||
record_layout_for_printing(&cx, layout);
|
||||
}
|
||||
|
||||
|
@ -79,31 +78,58 @@ fn layout_of<'tcx>(
|
|||
Ok(layout)
|
||||
}
|
||||
|
||||
fn error<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
err: LayoutError<'tcx>,
|
||||
fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> {
|
||||
cx.tcx().arena.alloc(err)
|
||||
}
|
||||
|
||||
fn map_error<'tcx>(
|
||||
cx: &LayoutCx<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
err: LayoutCalculatorError<TyAndLayout<'tcx>>,
|
||||
) -> &'tcx LayoutError<'tcx> {
|
||||
cx.tcx.arena.alloc(err)
|
||||
let err = match err {
|
||||
LayoutCalculatorError::SizeOverflow => {
|
||||
// This is sometimes not a compile error in `check` builds.
|
||||
// See `tests/ui/limits/huge-enum.rs` for an example.
|
||||
LayoutError::SizeOverflow(ty)
|
||||
}
|
||||
LayoutCalculatorError::UnexpectedUnsized(field) => {
|
||||
// This is sometimes not a compile error if there are trivially false where clauses.
|
||||
// See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
|
||||
assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
|
||||
if !field.ty.is_sized(cx.tcx(), cx.param_env) {
|
||||
cx.tcx().dcx().delayed_bug(format!(
|
||||
"encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
|
||||
));
|
||||
}
|
||||
LayoutError::Unknown(ty)
|
||||
}
|
||||
LayoutCalculatorError::EmptyUnion => {
|
||||
// This is always a compile error.
|
||||
cx.tcx().dcx().delayed_bug(format!("computed layout of empty union: {ty:?}"));
|
||||
LayoutError::Unknown(ty)
|
||||
}
|
||||
};
|
||||
error(cx, err)
|
||||
}
|
||||
|
||||
fn univariant_uninterned<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
fields: &IndexSlice<FieldIdx, Layout<'_>>,
|
||||
fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
|
||||
repr: &ReprOptions,
|
||||
kind: StructKind,
|
||||
) -> Result<LayoutS<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
|
||||
let dl = cx.data_layout();
|
||||
let pack = repr.pack;
|
||||
if pack.is_some() && repr.align.is_some() {
|
||||
cx.tcx.dcx().bug("struct cannot be packed and aligned");
|
||||
cx.tcx().dcx().bug("struct cannot be packed and aligned");
|
||||
}
|
||||
|
||||
cx.univariant(dl, fields, repr, kind).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))
|
||||
cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
|
||||
}
|
||||
|
||||
fn layout_of_uncached<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
// Types that reference `ty::Error` pessimistically don't have a meaningful layout.
|
||||
|
@ -113,7 +139,7 @@ fn layout_of_uncached<'tcx>(
|
|||
return Err(error(cx, LayoutError::ReferencesError(guar)));
|
||||
}
|
||||
|
||||
let tcx = cx.tcx;
|
||||
let tcx = cx.tcx();
|
||||
let param_env = cx.param_env;
|
||||
let dl = cx.data_layout();
|
||||
let scalar_unit = |value: Primitive| {
|
||||
|
@ -123,9 +149,10 @@ fn layout_of_uncached<'tcx>(
|
|||
};
|
||||
let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value)));
|
||||
|
||||
let univariant = |fields: &IndexSlice<FieldIdx, Layout<'_>>, repr: &ReprOptions, kind| {
|
||||
Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
|
||||
};
|
||||
let univariant =
|
||||
|fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| {
|
||||
Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
|
||||
};
|
||||
debug_assert!(!ty.has_non_region_infer());
|
||||
|
||||
Ok(match *ty.kind() {
|
||||
|
@ -191,7 +218,7 @@ fn layout_of_uncached<'tcx>(
|
|||
}
|
||||
|
||||
// The never type.
|
||||
ty::Never => tcx.mk_layout(cx.layout_of_never_type()),
|
||||
ty::Never => tcx.mk_layout(cx.calc.layout_of_never_type()),
|
||||
|
||||
// Potentially-wide pointers.
|
||||
ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
|
||||
|
@ -267,7 +294,7 @@ fn layout_of_uncached<'tcx>(
|
|||
};
|
||||
|
||||
// Effectively a (ptr, meta) tuple.
|
||||
tcx.mk_layout(cx.scalar_pair(data_ptr, metadata))
|
||||
tcx.mk_layout(cx.calc.scalar_pair(data_ptr, metadata))
|
||||
}
|
||||
|
||||
ty::Dynamic(_, _, ty::DynStar) => {
|
||||
|
@ -275,7 +302,7 @@ fn layout_of_uncached<'tcx>(
|
|||
data.valid_range_mut().start = 0;
|
||||
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
|
||||
vtable.valid_range_mut().start = 1;
|
||||
tcx.mk_layout(cx.scalar_pair(data, vtable))
|
||||
tcx.mk_layout(cx.calc.scalar_pair(data, vtable))
|
||||
}
|
||||
|
||||
// Arrays and slices.
|
||||
|
@ -363,9 +390,7 @@ fn layout_of_uncached<'tcx>(
|
|||
ty::Closure(_, args) => {
|
||||
let tys = args.as_closure().upvar_tys();
|
||||
univariant(
|
||||
&tys.iter()
|
||||
.map(|ty| Ok(cx.layout_of(ty)?.layout))
|
||||
.try_collect::<IndexVec<_, _>>()?,
|
||||
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized,
|
||||
)?
|
||||
|
@ -374,9 +399,7 @@ fn layout_of_uncached<'tcx>(
|
|||
ty::CoroutineClosure(_, args) => {
|
||||
let tys = args.as_coroutine_closure().upvar_tys();
|
||||
univariant(
|
||||
&tys.iter()
|
||||
.map(|ty| Ok(cx.layout_of(ty)?.layout))
|
||||
.try_collect::<IndexVec<_, _>>()?,
|
||||
&tys.iter().map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized,
|
||||
)?
|
||||
|
@ -387,7 +410,7 @@ fn layout_of_uncached<'tcx>(
|
|||
if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
|
||||
|
||||
univariant(
|
||||
&tys.iter().map(|k| Ok(cx.layout_of(k)?.layout)).try_collect::<IndexVec<_, _>>()?,
|
||||
&tys.iter().map(|k| cx.layout_of(k)).try_collect::<IndexVec<_, _>>()?,
|
||||
&ReprOptions::default(),
|
||||
kind,
|
||||
)?
|
||||
|
@ -527,14 +550,14 @@ fn layout_of_uncached<'tcx>(
|
|||
.map(|v| {
|
||||
v.fields
|
||||
.iter()
|
||||
.map(|field| Ok(cx.layout_of(field.ty(tcx, args))?.layout))
|
||||
.map(|field| cx.layout_of(field.ty(tcx, args)))
|
||||
.try_collect::<IndexVec<_, _>>()
|
||||
})
|
||||
.try_collect::<IndexVec<VariantIdx, _>>()?;
|
||||
|
||||
if def.is_union() {
|
||||
if def.repr().pack.is_some() && def.repr().align.is_some() {
|
||||
cx.tcx.dcx().span_delayed_bug(
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(def.did()),
|
||||
"union cannot be packed and aligned",
|
||||
);
|
||||
|
@ -542,45 +565,12 @@ fn layout_of_uncached<'tcx>(
|
|||
}
|
||||
|
||||
return Ok(tcx.mk_layout(
|
||||
cx.layout_of_union(&def.repr(), &variants)
|
||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
|
||||
cx.calc
|
||||
.layout_of_union(&def.repr(), &variants)
|
||||
.map_err(|err| map_error(cx, ty, err))?,
|
||||
));
|
||||
}
|
||||
|
||||
let err_if_unsized = |field: &FieldDef, err_msg: &str| {
|
||||
let field_ty = tcx.type_of(field.did);
|
||||
let is_unsized = tcx
|
||||
.try_instantiate_and_normalize_erasing_regions(args, cx.param_env, field_ty)
|
||||
.map(|f| !f.is_sized(tcx, cx.param_env))
|
||||
.map_err(|e| {
|
||||
error(
|
||||
cx,
|
||||
LayoutError::NormalizationFailure(field_ty.instantiate_identity(), e),
|
||||
)
|
||||
})?;
|
||||
|
||||
if is_unsized {
|
||||
cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned());
|
||||
Err(error(cx, LayoutError::Unknown(ty)))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
if def.is_struct() {
|
||||
if let Some((_, fields_except_last)) =
|
||||
def.non_enum_variant().fields.raw.split_last()
|
||||
{
|
||||
for f in fields_except_last {
|
||||
err_if_unsized(f, "only the last field of a struct can be unsized")?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for f in def.all_fields() {
|
||||
err_if_unsized(f, &format!("{}s cannot have unsized fields", def.descr()))?;
|
||||
}
|
||||
}
|
||||
|
||||
let get_discriminant_type =
|
||||
|min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);
|
||||
|
||||
|
@ -603,19 +593,24 @@ fn layout_of_uncached<'tcx>(
|
|||
!tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, param_env)
|
||||
});
|
||||
|
||||
let Some(layout) = cx.layout_of_struct_or_enum(
|
||||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
def.is_unsafe_cell(),
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
dont_niche_optimize_enum,
|
||||
!maybe_unsized,
|
||||
) else {
|
||||
return Err(error(cx, LayoutError::SizeOverflow(ty)));
|
||||
};
|
||||
let layout = cx
|
||||
.calc
|
||||
.layout_of_struct_or_enum(
|
||||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
def.is_unsafe_cell(),
|
||||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
dont_niche_optimize_enum,
|
||||
!maybe_unsized,
|
||||
)
|
||||
.map_err(|err| map_error(cx, ty, err))?;
|
||||
|
||||
if !maybe_unsized && layout.is_unsized() {
|
||||
bug!("got unsized layout for type that cannot be unsized {ty:?}: {layout:#?}");
|
||||
}
|
||||
|
||||
// If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
|
||||
if cfg!(debug_assertions)
|
||||
|
@ -624,9 +619,9 @@ fn layout_of_uncached<'tcx>(
|
|||
{
|
||||
let mut variants = variants;
|
||||
let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
|
||||
*variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement.layout;
|
||||
*variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement;
|
||||
|
||||
let Some(unsized_layout) = cx.layout_of_struct_or_enum(
|
||||
let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum(
|
||||
&def.repr(),
|
||||
&variants,
|
||||
def.is_enum(),
|
||||
|
@ -809,13 +804,13 @@ fn coroutine_saved_local_eligibility(
|
|||
|
||||
/// Compute the full coroutine layout.
|
||||
fn coroutine_layout<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
def_id: hir::def_id::DefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
use SavedLocalEligibility::*;
|
||||
let tcx = cx.tcx;
|
||||
let tcx = cx.tcx();
|
||||
let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args);
|
||||
|
||||
let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else {
|
||||
|
@ -832,21 +827,24 @@ fn coroutine_layout<'tcx>(
|
|||
let max_discr = (info.variant_fields.len() - 1) as u128;
|
||||
let discr_int = Integer::fit_unsigned(max_discr);
|
||||
let tag = Scalar::Initialized {
|
||||
value: Primitive::Int(discr_int, false),
|
||||
value: Primitive::Int(discr_int, /* signed = */ false),
|
||||
valid_range: WrappingRange { start: 0, end: max_discr },
|
||||
};
|
||||
let tag_layout = cx.tcx.mk_layout(LayoutS::scalar(cx, tag));
|
||||
let tag_layout = TyAndLayout {
|
||||
ty: discr_int.to_ty(tcx, /* signed = */ false),
|
||||
layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
|
||||
};
|
||||
|
||||
let promoted_layouts = ineligible_locals.iter().map(|local| {
|
||||
let field_ty = instantiate_field(info.field_tys[local].ty);
|
||||
let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty);
|
||||
Ok(cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span)?.layout)
|
||||
cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span)
|
||||
});
|
||||
let prefix_layouts = args
|
||||
.as_coroutine()
|
||||
.prefix_tys()
|
||||
.iter()
|
||||
.map(|ty| Ok(cx.layout_of(ty)?.layout))
|
||||
.map(|ty| cx.layout_of(ty))
|
||||
.chain(iter::once(Ok(tag_layout)))
|
||||
.chain(promoted_layouts)
|
||||
.try_collect::<IndexVec<_, _>>()?;
|
||||
|
@ -920,9 +918,7 @@ fn coroutine_layout<'tcx>(
|
|||
let mut variant = univariant_uninterned(
|
||||
cx,
|
||||
ty,
|
||||
&variant_only_tys
|
||||
.map(|ty| Ok(cx.layout_of(ty)?.layout))
|
||||
.try_collect::<IndexVec<_, _>>()?,
|
||||
&variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::<IndexVec<_, _>>()?,
|
||||
&ReprOptions::default(),
|
||||
StructKind::Prefixed(prefix_size, prefix_align.abi),
|
||||
)?;
|
||||
|
@ -1017,7 +1013,7 @@ fn coroutine_layout<'tcx>(
|
|||
Ok(layout)
|
||||
}
|
||||
|
||||
fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: TyAndLayout<'tcx>) {
|
||||
fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) {
|
||||
// Ignore layouts that are done with non-empty environments or
|
||||
// non-monomorphic layouts, as the user only wants to see the stuff
|
||||
// resulting from the final codegen session.
|
||||
|
@ -1028,7 +1024,7 @@ fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: T
|
|||
// (delay format until we actually need it)
|
||||
let record = |kind, packed, opt_discr_size, variants| {
|
||||
let type_desc = with_no_trimmed_paths!(format!("{}", layout.ty));
|
||||
cx.tcx.sess.code_stats.record_type_size(
|
||||
cx.tcx().sess.code_stats.record_type_size(
|
||||
kind,
|
||||
type_desc,
|
||||
layout.align.abi,
|
||||
|
@ -1068,7 +1064,7 @@ fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: T
|
|||
}
|
||||
|
||||
fn variant_info_for_adt<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
adt_def: AdtDef<'tcx>,
|
||||
) -> (Vec<VariantInfo>, Option<Size>) {
|
||||
|
@ -1140,7 +1136,7 @@ fn variant_info_for_adt<'tcx>(
|
|||
}
|
||||
|
||||
fn variant_info_for_coroutine<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
cx: &LayoutCx<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
|
@ -1151,8 +1147,8 @@ fn variant_info_for_coroutine<'tcx>(
|
|||
return (vec![], None);
|
||||
};
|
||||
|
||||
let coroutine = cx.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()).unwrap();
|
||||
let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
|
||||
let coroutine = cx.tcx().coroutine_layout(def_id, args.as_coroutine().kind_ty()).unwrap();
|
||||
let upvar_names = cx.tcx().closure_saved_names_of_captured_variables(def_id);
|
||||
|
||||
let mut upvars_size = Size::ZERO;
|
||||
let upvar_fields: Vec<_> = args
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout};
|
||||
use rustc_target::abi::*;
|
||||
|
||||
/// Enforce some basic invariants on layouts.
|
||||
pub(super) fn sanity_check_layout<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
layout: &TyAndLayout<'tcx>,
|
||||
) {
|
||||
pub(super) fn sanity_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
|
||||
let tcx = cx.tcx();
|
||||
|
||||
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
||||
if layout.ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
|
||||
if layout.ty.is_privately_uninhabited(tcx, cx.param_env) {
|
||||
assert!(layout.abi.is_uninhabited());
|
||||
}
|
||||
|
||||
if layout.size.bytes() % layout.align.abi.bytes() != 0 {
|
||||
bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
|
||||
}
|
||||
if layout.size.bytes() >= cx.tcx.data_layout.obj_size_bound() {
|
||||
if layout.size.bytes() >= tcx.data_layout.obj_size_bound() {
|
||||
bug!("size is too large, in the following layout:\n{layout:#?}");
|
||||
}
|
||||
|
||||
|
@ -28,8 +26,8 @@ pub(super) fn sanity_check_layout<'tcx>(
|
|||
}
|
||||
|
||||
/// Yields non-ZST fields of the type
|
||||
fn non_zst_fields<'a, 'tcx>(
|
||||
cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
fn non_zst_fields<'tcx, 'a>(
|
||||
cx: &'a LayoutCx<'tcx>,
|
||||
layout: &'a TyAndLayout<'tcx>,
|
||||
) -> impl Iterator<Item = (Size, TyAndLayout<'tcx>)> + 'a {
|
||||
(0..layout.layout.fields().count()).filter_map(|i| {
|
||||
|
@ -43,10 +41,7 @@ pub(super) fn sanity_check_layout<'tcx>(
|
|||
})
|
||||
}
|
||||
|
||||
fn skip_newtypes<'tcx>(
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
layout: &TyAndLayout<'tcx>,
|
||||
) -> TyAndLayout<'tcx> {
|
||||
fn skip_newtypes<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) -> TyAndLayout<'tcx> {
|
||||
if matches!(layout.layout.variants(), Variants::Multiple { .. }) {
|
||||
// Definitely not a newtype of anything.
|
||||
return *layout;
|
||||
|
@ -69,7 +64,7 @@ pub(super) fn sanity_check_layout<'tcx>(
|
|||
*layout
|
||||
}
|
||||
|
||||
fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) {
|
||||
fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
|
||||
// Verify the ABI mandated alignment and size.
|
||||
let align = layout.abi.inherent_align(cx).map(|align| align.abi);
|
||||
let size = layout.abi.inherent_size(cx);
|
||||
|
|
|
@ -975,9 +975,17 @@ pub trait UpperHex {
|
|||
/// `p` formatting.
|
||||
///
|
||||
/// The `Pointer` trait should format its output as a memory location. This is commonly presented
|
||||
/// as hexadecimal.
|
||||
/// as hexadecimal. For more information on formatters, see [the module-level documentation][module].
|
||||
///
|
||||
/// For more information on formatters, see [the module-level documentation][module].
|
||||
/// Printing of pointers is not a reliable way to discover how Rust programs are implemented.
|
||||
/// The act of reading an address changes the program itself, and may change how the data is represented
|
||||
/// in memory, and may affect which optimizations are applied to the code.
|
||||
///
|
||||
/// The printed pointer values are not guaranteed to be stable nor unique identifiers of objects.
|
||||
/// Rust allows moving values to different memory locations, and may reuse the same memory locations
|
||||
/// for different purposes.
|
||||
///
|
||||
/// There is no guarantee that the printed value can be converted back to a pointer.
|
||||
///
|
||||
/// [module]: ../../std/fmt/index.html
|
||||
///
|
||||
|
|
|
@ -1910,10 +1910,14 @@ impl crate::error::Error for ExitStatusError {}
|
|||
/// to its parent under normal termination.
|
||||
///
|
||||
/// `ExitCode` is intended to be consumed only by the standard library (via
|
||||
/// [`Termination::report()`]), and intentionally does not provide accessors like
|
||||
/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the
|
||||
/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From<u8> for
|
||||
/// ExitCode` for constructing other arbitrary exit codes.
|
||||
/// [`Termination::report()`]). For forwards compatibility with potentially
|
||||
/// unusual targets, this type currently does not provide `Eq`, `Hash`, or
|
||||
/// access to the raw value. This type does provide `PartialEq` for
|
||||
/// comparison, but note that there may potentially be multiple failure
|
||||
/// codes, some of which will _not_ compare equal to `ExitCode::FAILURE`.
|
||||
/// The standard library provides the canonical `SUCCESS` and `FAILURE`
|
||||
/// exit codes as well as `From<u8> for ExitCode` for constructing other
|
||||
/// arbitrary exit codes.
|
||||
///
|
||||
/// # Portability
|
||||
///
|
||||
|
@ -1952,7 +1956,7 @@ impl crate::error::Error for ExitStatusError {}
|
|||
/// ExitCode::SUCCESS
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[stable(feature = "process_exitcode", since = "1.61.0")]
|
||||
pub struct ExitCode(imp::ExitCode);
|
||||
|
||||
|
|
|
@ -1013,6 +1013,14 @@ macro_rules! tool_doc {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: make sure to register these in `Builder::get_step_description`.
|
||||
tool_doc!(
|
||||
BuildHelper,
|
||||
"src/tools/build_helper",
|
||||
rustc_tool = false,
|
||||
is_library = true,
|
||||
crates = ["build_helper"]
|
||||
);
|
||||
tool_doc!(Rustdoc, "src/tools/rustdoc", crates = ["rustdoc", "rustdoc-json-types"]);
|
||||
tool_doc!(Rustfmt, "src/tools/rustfmt", crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]);
|
||||
tool_doc!(Clippy, "src/tools/clippy", crates = ["clippy_config", "clippy_utils"]);
|
||||
|
|
|
@ -944,6 +944,7 @@ impl<'a> Builder<'a> {
|
|||
doc::Bootstrap,
|
||||
doc::Releases,
|
||||
doc::RunMakeSupport,
|
||||
doc::BuildHelper,
|
||||
),
|
||||
Kind::Dist => describe!(
|
||||
dist::Docs,
|
||||
|
|
|
@ -552,11 +552,7 @@ impl Build {
|
|||
// Look for `submodule.$name.path = $path`
|
||||
// Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
|
||||
let submodule = line.split_once(' ').unwrap().1;
|
||||
let path = Path::new(submodule);
|
||||
// Don't update the submodule unless it's already been cloned.
|
||||
if GitInfo::new(false, path).is_managed_git_subrepository() {
|
||||
self.config.update_submodule(submodule);
|
||||
}
|
||||
self.update_existing_submodule(submodule);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ pub fn create_ecx<'tcx>(
|
|||
config: &MiriConfig,
|
||||
) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let layout_cx = LayoutCx { tcx, param_env };
|
||||
let layout_cx = LayoutCx::new(tcx, param_env);
|
||||
let mut ecx =
|
||||
InterpCx::new(tcx, rustc_span::DUMMY_SP, param_env, MiriMachine::new(config, layout_cx));
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc_middle::{
|
|||
query::TyCtxtAt,
|
||||
ty::{
|
||||
self,
|
||||
layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
|
||||
layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout},
|
||||
Instance, Ty, TyCtxt,
|
||||
},
|
||||
};
|
||||
|
@ -381,8 +381,8 @@ pub struct PrimitiveLayouts<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> PrimitiveLayouts<'tcx> {
|
||||
fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> {
|
||||
let tcx = layout_cx.tcx;
|
||||
fn new(layout_cx: LayoutCx<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> {
|
||||
let tcx = layout_cx.tcx();
|
||||
let mut_raw_ptr = Ty::new_mut_ptr(tcx, tcx.types.unit);
|
||||
let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
|
||||
Ok(Self {
|
||||
|
@ -596,14 +596,13 @@ pub struct MiriMachine<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> MiriMachine<'tcx> {
|
||||
pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self {
|
||||
let tcx = layout_cx.tcx;
|
||||
pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self {
|
||||
let tcx = layout_cx.tcx();
|
||||
let local_crates = helpers::get_local_crates(tcx);
|
||||
let layouts =
|
||||
PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
|
||||
let profiler = config.measureme_out.as_ref().map(|out| {
|
||||
let crate_name = layout_cx
|
||||
.tcx
|
||||
let crate_name = tcx
|
||||
.sess
|
||||
.opts
|
||||
.crate_name
|
||||
|
@ -701,7 +700,7 @@ impl<'tcx> MiriMachine<'tcx> {
|
|||
clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
|
||||
#[cfg(unix)]
|
||||
native_lib: config.native_lib.as_ref().map(|lib_file_path| {
|
||||
let target_triple = layout_cx.tcx.sess.opts.target_triple.triple();
|
||||
let target_triple = tcx.sess.opts.target_triple.triple();
|
||||
// Check if host target == the session target.
|
||||
if env!("TARGET") != target_triple {
|
||||
panic!(
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
//! Compute the binary representation of a type
|
||||
|
||||
use std::{borrow::Cow, fmt};
|
||||
use std::fmt;
|
||||
|
||||
use base_db::salsa::Cycle;
|
||||
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
|
||||
use hir_def::{
|
||||
layout::{
|
||||
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions,
|
||||
Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
|
||||
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS,
|
||||
Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
|
||||
},
|
||||
LocalFieldId, StructId,
|
||||
};
|
||||
|
@ -15,7 +15,6 @@ use la_arena::{Idx, RawIdx};
|
|||
use rustc_abi::AddressSpace;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
|
@ -107,19 +106,24 @@ impl fmt::Display for LayoutError {
|
|||
}
|
||||
}
|
||||
|
||||
struct LayoutCx<'a> {
|
||||
target: &'a TargetDataLayout,
|
||||
impl<F> From<LayoutCalculatorError<F>> for LayoutError {
|
||||
fn from(err: LayoutCalculatorError<F>) -> Self {
|
||||
match err {
|
||||
LayoutCalculatorError::UnexpectedUnsized(_) | LayoutCalculatorError::EmptyUnion => {
|
||||
LayoutError::Unknown
|
||||
}
|
||||
LayoutCalculatorError::SizeOverflow => LayoutError::SizeOverflow,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LayoutCalculator for LayoutCx<'a> {
|
||||
type TargetDataLayoutRef = &'a TargetDataLayout;
|
||||
struct LayoutCx<'a> {
|
||||
calc: LayoutCalculator<&'a TargetDataLayout>,
|
||||
}
|
||||
|
||||
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
|
||||
never!("{}", txt.into());
|
||||
}
|
||||
|
||||
fn current_data_layout(&self) -> &'a TargetDataLayout {
|
||||
self.target
|
||||
impl<'a> LayoutCx<'a> {
|
||||
fn new(target: &'a TargetDataLayout) -> Self {
|
||||
Self { calc: LayoutCalculator::new(target) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,8 +209,8 @@ pub fn layout_of_ty_query(
|
|||
let Ok(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = cx.current_data_layout();
|
||||
let dl = &*target;
|
||||
let cx = LayoutCx::new(dl);
|
||||
let ty = normalize(db, trait_env.clone(), ty);
|
||||
let result = match ty.kind(Interner) {
|
||||
TyKind::Adt(AdtId(def), subst) => {
|
||||
|
@ -281,7 +285,7 @@ pub fn layout_of_ty_query(
|
|||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
|
||||
let fields = fields.iter().collect::<IndexVec<_, _>>();
|
||||
cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
|
||||
cx.calc.univariant(&fields, &ReprOptions::default(), kind)?
|
||||
}
|
||||
TyKind::Array(element, count) => {
|
||||
let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64;
|
||||
|
@ -367,12 +371,12 @@ pub fn layout_of_ty_query(
|
|||
};
|
||||
|
||||
// Effectively a (ptr, meta) tuple.
|
||||
cx.scalar_pair(data_ptr, metadata)
|
||||
cx.calc.scalar_pair(data_ptr, metadata)
|
||||
}
|
||||
TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?,
|
||||
TyKind::Never => cx.layout_of_never_type(),
|
||||
TyKind::FnDef(_, _) => layout_of_unit(&cx)?,
|
||||
TyKind::Never => cx.calc.layout_of_never_type(),
|
||||
TyKind::Dyn(_) | TyKind::Foreign(_) => {
|
||||
let mut unit = layout_of_unit(&cx, dl)?;
|
||||
let mut unit = layout_of_unit(&cx)?;
|
||||
match &mut unit.abi {
|
||||
Abi::Aggregate { sized } => *sized = false,
|
||||
_ => return Err(LayoutError::Unknown),
|
||||
|
@ -414,8 +418,7 @@ pub fn layout_of_ty_query(
|
|||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
|
||||
let fields = fields.iter().collect::<IndexVec<_, _>>();
|
||||
cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized)
|
||||
.ok_or(LayoutError::Unknown)?
|
||||
cx.calc.univariant(&fields, &ReprOptions::default(), StructKind::AlwaysSized)?
|
||||
}
|
||||
TyKind::Coroutine(_, _) | TyKind::CoroutineWitness(_, _) => {
|
||||
return Err(LayoutError::NotImplemented)
|
||||
|
@ -447,14 +450,14 @@ pub fn layout_of_ty_recover(
|
|||
Err(LayoutError::RecursiveTypeWithoutIndirection)
|
||||
}
|
||||
|
||||
fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
|
||||
cx.univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
|
||||
dl,
|
||||
IndexSlice::empty(),
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized,
|
||||
)
|
||||
.ok_or(LayoutError::Unknown)
|
||||
fn layout_of_unit(cx: &LayoutCx<'_>) -> Result<Layout, LayoutError> {
|
||||
cx.calc
|
||||
.univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
|
||||
IndexSlice::empty(),
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{cmp, ops::Bound};
|
|||
use base_db::salsa::Cycle;
|
||||
use hir_def::{
|
||||
data::adt::VariantData,
|
||||
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
|
||||
layout::{Integer, ReprOptions, TargetDataLayout},
|
||||
AdtId, VariantId,
|
||||
};
|
||||
use intern::sym;
|
||||
|
@ -36,8 +36,8 @@ pub fn layout_of_adt_query(
|
|||
let Ok(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = cx.current_data_layout();
|
||||
let dl = &*target;
|
||||
let cx = LayoutCx::new(dl);
|
||||
let handle_variant = |def: VariantId, var: &VariantData| {
|
||||
var.fields()
|
||||
.iter()
|
||||
|
@ -73,9 +73,9 @@ pub fn layout_of_adt_query(
|
|||
.collect::<SmallVec<[_; 1]>>();
|
||||
let variants = variants.iter().map(|it| it.iter().collect()).collect::<IndexVec<_, _>>();
|
||||
let result = if matches!(def, AdtId::UnionId(..)) {
|
||||
cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)?
|
||||
cx.calc.layout_of_union(&repr, &variants)?
|
||||
} else {
|
||||
cx.layout_of_struct_or_enum(
|
||||
cx.calc.layout_of_struct_or_enum(
|
||||
&repr,
|
||||
&variants,
|
||||
matches!(def, AdtId::EnumId(..)),
|
||||
|
@ -103,8 +103,7 @@ pub fn layout_of_adt_query(
|
|||
.next()
|
||||
.and_then(|it| it.iter().last().map(|it| !it.is_unsized()))
|
||||
.unwrap_or(true),
|
||||
)
|
||||
.ok_or(LayoutError::SizeOverflow)?
|
||||
)?
|
||||
};
|
||||
Ok(Arc::new(result))
|
||||
}
|
||||
|
|
30
tests/assembly/simd/reduce-fadd-unordered.rs
Normal file
30
tests/assembly/simd/reduce-fadd-unordered.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
//@ revisions: x86_64 aarch64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O
|
||||
//@[aarch64] only-aarch64
|
||||
//@[x86_64] only-x86_64
|
||||
//@[x86_64] compile-flags: -Ctarget-feature=+sse3
|
||||
//@ ignore-sgx Test incompatible with LVI mitigations
|
||||
#![feature(portable_simd)]
|
||||
#![feature(core_intrinsics)]
|
||||
use std::intrinsics::simd as intrinsics;
|
||||
use std::simd::*;
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/130028
|
||||
// This intrinsic produces much worse code if you use +0.0 instead of -0.0 because
|
||||
// +0.0 isn't as easy to algebraically reassociate, even using LLVM's reassoc attribute!
|
||||
// It would emit about an extra fadd, depending on the architecture.
|
||||
|
||||
// CHECK-LABEL: reduce_fadd_negative_zero
|
||||
pub unsafe fn reduce_fadd_negative_zero(v: f32x4) -> f32 {
|
||||
// x86_64: addps
|
||||
// x86_64-NEXT: movshdup
|
||||
// x86_64-NEXT: addss
|
||||
// x86_64-NOT: xorps
|
||||
|
||||
// aarch64: faddp
|
||||
// aarch64-NEXT: faddp
|
||||
|
||||
// CHECK-NOT: {{f?}}add{{p?s*}}
|
||||
// CHECK: ret
|
||||
intrinsics::simd_reduce_add_unordered(v)
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
//@ known-bug: #124182
|
||||
struct LazyLock<T> {
|
||||
data: (Copy, fn() -> T),
|
||||
}
|
||||
|
||||
impl<T> LazyLock<T> {
|
||||
pub const fn new(f: fn() -> T) -> LazyLock<T> {
|
||||
LazyLock { data: (None, f) }
|
||||
}
|
||||
}
|
||||
|
||||
struct A<T = i32>(Option<T>);
|
||||
|
||||
impl<T> Default for A<T> {
|
||||
fn default() -> Self {
|
||||
A(None)
|
||||
}
|
||||
}
|
||||
|
||||
static EMPTY_SET: LazyLock<A<i32>> = LazyLock::new(A::default);
|
||||
|
||||
fn main() {}
|
|
@ -1,21 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#126939
|
||||
|
||||
struct MySlice<T: Copy>(bool, T);
|
||||
type MySliceBool = MySlice<[bool]>;
|
||||
|
||||
use std::mem;
|
||||
|
||||
struct P2<T> {
|
||||
a: T,
|
||||
b: MySliceBool,
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($t:ty, $align:expr) => ({
|
||||
assert_eq!(mem::align_of::<$t>(), $align);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
check!(P2<u8>, 1);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#129850
|
||||
|
||||
pub trait Foo2 {
|
||||
fn bar<'a: 'a>(&'a mut self) -> impl Sized + use<'static>;
|
||||
}
|
||||
|
||||
impl Foo2 for () {
|
||||
fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a {}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#130372
|
||||
|
||||
pub fn variadic_fn(n: usize, mut args: ...) {}
|
||||
|
||||
reuse variadic_fn;
|
||||
|
||||
fn main() {
|
||||
variadic_fn();
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#130372
|
||||
|
||||
pub fn test_va_copy(_: u64, mut ap: ...) {}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
test_va_copy();
|
||||
|
||||
call(x);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#130372
|
||||
|
||||
fn bar() -> impl Fn() {
|
||||
wrap()
|
||||
}
|
||||
|
||||
fn wrap(...: impl ...) -> impl Fn() {}
|
|
@ -1,5 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#130399
|
||||
|
||||
fn elided(main: &()) -> impl Sized + use<main> {}
|
||||
|
||||
fn main() {}
|
|
@ -1,4 +1,3 @@
|
|||
//@ known-bug: rust-lang/rust#129262
|
||||
//@ compile-flags: -Zvalidate-mir --edition=2018 --crate-type=lib -Copt-level=3
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
@ -11,6 +10,7 @@ fn needs_fn_mut<T>(mut x: impl FnMut() -> T) {
|
|||
|
||||
fn hello(x: Ty) {
|
||||
needs_fn_mut(async || {
|
||||
//~^ ERROR cannot move out of `x`
|
||||
x.hello();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
error[E0507]: cannot move out of `x` which is behind a mutable reference
|
||||
--> $DIR/closure-shim-borrowck-error.rs:12:18
|
||||
|
|
||||
LL | needs_fn_mut(async || {
|
||||
| ^^^^^^^^ `x` is moved here
|
||||
LL |
|
||||
LL | x.hello();
|
||||
| -
|
||||
| |
|
||||
| variable moved due to use in coroutine
|
||||
| move occurs because `x` has type `Ty`, which does not implement the `Copy` trait
|
||||
|
|
||||
note: if `Ty` implemented `Clone`, you could clone the value
|
||||
--> $DIR/closure-shim-borrowck-error.rs:18:1
|
||||
|
|
||||
LL | x.hello();
|
||||
| - you could clone this value
|
||||
...
|
||||
LL | struct Ty;
|
||||
| ^^^^^^^^^ consider implementing `Clone` for this type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0507`.
|
|
@ -0,0 +1,19 @@
|
|||
//@ aux-build:block-on.rs
|
||||
//@ edition: 2021
|
||||
//@ build-pass
|
||||
//@ compile-flags: -Cdebuginfo=2
|
||||
|
||||
#![feature(async_closure)]
|
||||
|
||||
extern crate block_on;
|
||||
|
||||
async fn call_once(f: impl async FnOnce()) {
|
||||
f().await;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
block_on::block_on(async {
|
||||
let async_closure = async move || {};
|
||||
call_once(async_closure).await;
|
||||
});
|
||||
}
|
4
tests/ui/error-codes/E0799.rs
Normal file
4
tests/ui/error-codes/E0799.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
fn test() -> impl Sized + use<main> {}
|
||||
//~^ ERROR E0799
|
||||
|
||||
fn main() {}
|
9
tests/ui/error-codes/E0799.stderr
Normal file
9
tests/ui/error-codes/E0799.stderr
Normal file
|
@ -0,0 +1,9 @@
|
|||
error[E0799]: expected type or const parameter, found function `main`
|
||||
--> $DIR/E0799.rs:1:31
|
||||
|
|
||||
LL | fn test() -> impl Sized + use<main> {}
|
||||
| ^^^^ not a type or const parameter
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0799`.
|
4
tests/ui/error-codes/E0800.rs
Normal file
4
tests/ui/error-codes/E0800.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
fn test() -> impl Sized + use<Missing> {}
|
||||
//~^ ERROR E0800
|
||||
|
||||
fn main() {}
|
9
tests/ui/error-codes/E0800.stderr
Normal file
9
tests/ui/error-codes/E0800.stderr
Normal file
|
@ -0,0 +1,9 @@
|
|||
error[E0800]: cannot find type or const parameter `Missing` in this scope
|
||||
--> $DIR/E0800.rs:1:31
|
||||
|
|
||||
LL | fn test() -> impl Sized + use<Missing> {}
|
||||
| ^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0800`.
|
|
@ -1,8 +1,8 @@
|
|||
fn missing() -> impl Sized + use<T> {}
|
||||
//~^ ERROR cannot find type `T` in this scope
|
||||
//~^ ERROR cannot find type or const parameter `T` in this scope
|
||||
|
||||
fn missing_self() -> impl Sized + use<Self> {}
|
||||
//~^ ERROR cannot find type `Self` in this scope
|
||||
//~^ ERROR cannot find type or const parameter `Self` in this scope
|
||||
|
||||
struct MyType;
|
||||
impl MyType {
|
||||
|
@ -11,6 +11,9 @@ impl MyType {
|
|||
}
|
||||
|
||||
fn hello() -> impl Sized + use<hello> {}
|
||||
//~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function
|
||||
//~^ ERROR expected type or const parameter, found function `hello`
|
||||
|
||||
fn arg(x: ()) -> impl Sized + use<x> {}
|
||||
//~^ ERROR expected type or const parameter, found local variable `x`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0412]: cannot find type `T` in this scope
|
||||
error[E0800]: cannot find type or const parameter `T` in this scope
|
||||
--> $DIR/bad-params.rs:1:34
|
||||
|
|
||||
LL | fn missing() -> impl Sized + use<T> {}
|
||||
|
@ -9,7 +9,7 @@ help: you might be missing a type parameter
|
|||
LL | fn missing<T>() -> impl Sized + use<T> {}
|
||||
| +++
|
||||
|
||||
error[E0411]: cannot find type `Self` in this scope
|
||||
error[E0411]: cannot find type or const parameter `Self` in this scope
|
||||
--> $DIR/bad-params.rs:4:39
|
||||
|
|
||||
LL | fn missing_self() -> impl Sized + use<Self> {}
|
||||
|
@ -17,7 +17,19 @@ LL | fn missing_self() -> impl Sized + use<Self> {}
|
|||
| |
|
||||
| `Self` not allowed in a function
|
||||
|
||||
error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias
|
||||
error[E0799]: expected type or const parameter, found function `hello`
|
||||
--> $DIR/bad-params.rs:13:32
|
||||
|
|
||||
LL | fn hello() -> impl Sized + use<hello> {}
|
||||
| ^^^^^ not a type or const parameter
|
||||
|
||||
error[E0799]: expected type or const parameter, found local variable `x`
|
||||
--> $DIR/bad-params.rs:16:35
|
||||
|
|
||||
LL | fn arg(x: ()) -> impl Sized + use<x> {}
|
||||
| ^ not a type or const parameter
|
||||
|
||||
error[E0799]: `Self` can't be captured in `use<...>` precise captures list, since it is an alias
|
||||
--> $DIR/bad-params.rs:9:48
|
||||
|
|
||||
LL | impl MyType {
|
||||
|
@ -25,13 +37,7 @@ LL | impl MyType {
|
|||
LL | fn self_is_not_param() -> impl Sized + use<Self> {}
|
||||
| ^^^^
|
||||
|
||||
error: expected type or const parameter in `use<...>` precise captures list, found function
|
||||
--> $DIR/bad-params.rs:13:32
|
||||
|
|
||||
LL | fn hello() -> impl Sized + use<hello> {}
|
||||
| ^^^^^
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0411, E0412.
|
||||
Some errors have detailed explanations: E0411, E0799, E0800.
|
||||
For more information about an error, try `rustc --explain E0411`.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Make sure we don't ICE when an RPITIT captures more method args than the
|
||||
// trait definition, which is not allowed. Due to the default lifetime capture
|
||||
// rules of RPITITs, this is only doable if we use precise capturing.
|
||||
|
||||
pub trait Foo {
|
||||
fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
|
||||
//~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {}
|
||||
//~^ ERROR return type captures more lifetimes than trait definition
|
||||
//~| WARN impl trait in impl method signature does not match trait method signature
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,42 @@
|
|||
error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
|
||||
--> $DIR/rpitit-captures-more-method-lifetimes.rs:6:53
|
||||
|
|
||||
LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope
|
||||
|
||||
error: return type captures more lifetimes than trait definition
|
||||
--> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40
|
||||
|
|
||||
LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {}
|
||||
| --- ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| this lifetime was captured
|
||||
|
|
||||
note: hidden type must only reference lifetimes captured by this impl trait
|
||||
--> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40
|
||||
|
|
||||
LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: hidden type inferred to be `impl Sized + 'im`
|
||||
|
||||
warning: impl trait in impl method signature does not match trait method signature
|
||||
--> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40
|
||||
|
|
||||
LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>;
|
||||
| ---------------------- return type from trait method defined here
|
||||
...
|
||||
LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
||||
= note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
||||
= note: `#[warn(refining_impl_trait_reachable)]` on by default
|
||||
help: replace the return type so that it matches the trait
|
||||
|
|
||||
LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized {}
|
||||
| ~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
|
@ -76,3 +76,8 @@ impl S {
|
|||
|
||||
#[rustc_layout(debug)]
|
||||
type Impossible = (str, str); //~ ERROR: cannot be known at compilation time
|
||||
|
||||
// Test that computing the layout of an empty union doesn't ICE.
|
||||
#[rustc_layout(debug)]
|
||||
union EmptyUnion {} //~ ERROR: has an unknown layout
|
||||
//~^ ERROR: unions cannot have zero fields
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
error: unions cannot have zero fields
|
||||
--> $DIR/debug.rs:82:1
|
||||
|
|
||||
LL | union EmptyUnion {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: layout_of(E) = Layout {
|
||||
size: Size(12 bytes),
|
||||
align: AbiAndPrefAlign {
|
||||
|
@ -566,12 +572,18 @@ LL | type Impossible = (str, str);
|
|||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: only the last element of a tuple may have a dynamically sized type
|
||||
|
||||
error: the type `EmptyUnion` has an unknown layout
|
||||
--> $DIR/debug.rs:82:1
|
||||
|
|
||||
LL | union EmptyUnion {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
|
||||
--> $DIR/debug.rs:74:5
|
||||
|
|
||||
LL | const C: () = ();
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
14
tests/ui/layout/invalid-unsized-const-eval.rs
Normal file
14
tests/ui/layout/invalid-unsized-const-eval.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// issue: #124182
|
||||
|
||||
//! This test used to trip an assertion in const eval, because `layout_of(LazyLock)`
|
||||
//! returned `Ok` with an unsized layout when a sized layout was expected.
|
||||
//! It was fixed by making `layout_of` always return `Err` for types that
|
||||
//! contain unsized fields in unexpected locations.
|
||||
|
||||
struct LazyLock {
|
||||
data: (dyn Sync, ()), //~ ERROR the size for values of type
|
||||
}
|
||||
|
||||
static EMPTY_SET: LazyLock = todo!();
|
||||
|
||||
fn main() {}
|
12
tests/ui/layout/invalid-unsized-const-eval.stderr
Normal file
12
tests/ui/layout/invalid-unsized-const-eval.stderr
Normal file
|
@ -0,0 +1,12 @@
|
|||
error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time
|
||||
--> $DIR/invalid-unsized-const-eval.rs:9:11
|
||||
|
|
||||
LL | data: (dyn Sync, ()),
|
||||
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn Sync + 'static)`
|
||||
= note: only the last element of a tuple may have a dynamically sized type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
|
@ -1,6 +1,10 @@
|
|||
//@ known-bug: #127737
|
||||
// issue: #127737
|
||||
//@ check-pass
|
||||
//@ compile-flags: -Zmir-opt-level=5 --crate-type lib
|
||||
|
||||
//! This test is very similar to `invalid-unsized-const-eval.rs`, but also requires
|
||||
//! checking for unsized types in the last field of each enum variant.
|
||||
|
||||
pub trait TestTrait {
|
||||
type MyType;
|
||||
fn func() -> Option<Self>
|
17
tests/ui/layout/invalid-unsized-in-always-sized-tail.rs
Normal file
17
tests/ui/layout/invalid-unsized-in-always-sized-tail.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
// issue: rust-lang/rust#126939
|
||||
|
||||
//! This used to ICE, because the layout algorithm did not check for unsized types
|
||||
//! in the struct tail of always-sized types (i.e. those that cannot be unsized)
|
||||
//! and incorrectly returned an unsized layout.
|
||||
|
||||
struct MySlice<T>(T);
|
||||
type MySliceBool = MySlice<[bool]>;
|
||||
|
||||
struct P2 {
|
||||
b: MySliceBool,
|
||||
//~^ ERROR: the size for values of type `[bool]` cannot be known at compilation time
|
||||
}
|
||||
|
||||
static CHECK: () = assert!(align_of::<P2>() == 1);
|
||||
|
||||
fn main() {}
|
23
tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
Normal file
23
tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
Normal file
|
@ -0,0 +1,23 @@
|
|||
error[E0277]: the size for values of type `[bool]` cannot be known at compilation time
|
||||
--> $DIR/invalid-unsized-in-always-sized-tail.rs:11:8
|
||||
|
|
||||
LL | b: MySliceBool,
|
||||
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `[bool]`
|
||||
note: required by an implicit `Sized` bound in `MySlice`
|
||||
--> $DIR/invalid-unsized-in-always-sized-tail.rs:7:16
|
||||
|
|
||||
LL | struct MySlice<T>(T);
|
||||
| ^ required by the implicit `Sized` requirement on this type parameter in `MySlice`
|
||||
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
|
||||
--> $DIR/invalid-unsized-in-always-sized-tail.rs:7:16
|
||||
|
|
||||
LL | struct MySlice<T>(T);
|
||||
| ^ - ...if indirection were used here: `Box<T>`
|
||||
| |
|
||||
| this could be changed to `T: ?Sized`...
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
51
tests/ui/layout/trivial-bounds-sized.rs
Normal file
51
tests/ui/layout/trivial-bounds-sized.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
//@ check-pass
|
||||
|
||||
//! With trivial bounds, it is possible to have ADTs with unsized fields
|
||||
//! in arbitrary places. Test that we do not ICE for such types.
|
||||
|
||||
#![feature(trivial_bounds)]
|
||||
#![expect(trivial_bounds)]
|
||||
|
||||
struct Struct
|
||||
where
|
||||
[u8]: Sized,
|
||||
[i16]: Sized,
|
||||
{
|
||||
a: [u8],
|
||||
b: [i16],
|
||||
c: f32,
|
||||
}
|
||||
|
||||
union Union
|
||||
where
|
||||
[u8]: Copy,
|
||||
[i16]: Copy,
|
||||
{
|
||||
a: [u8],
|
||||
b: [i16],
|
||||
c: f32,
|
||||
}
|
||||
|
||||
enum Enum
|
||||
where
|
||||
[u8]: Sized,
|
||||
[i16]: Sized,
|
||||
{
|
||||
V1([u8], [i16]),
|
||||
V2([i16], f32),
|
||||
}
|
||||
|
||||
// This forces layout computation via the `variant_size_differences` lint.
|
||||
// FIXME: This could be made more robust, possibly with a variant of `rustc_layout`
|
||||
// that doesn't error.
|
||||
enum Check
|
||||
where
|
||||
[u8]: Copy,
|
||||
[i16]: Copy,
|
||||
{
|
||||
Struct(Struct),
|
||||
Union(Union),
|
||||
Enum(Enum),
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,4 +1,9 @@
|
|||
//@ known-bug: #123134
|
||||
//@ check-pass
|
||||
// issue: #123134
|
||||
|
||||
//! This is a variant of `trivial-bounds-sized.rs` that compiles without any
|
||||
//! feature gates and used to trigger a delayed bug.
|
||||
|
||||
trait Api: Sized {
|
||||
type Device: ?Sized;
|
||||
}
|
||||
|
@ -7,7 +12,7 @@ struct OpenDevice<A: Api>
|
|||
where
|
||||
A::Device: Sized,
|
||||
{
|
||||
device: A::Device,
|
||||
device: A::Device, // <- this is the type that ends up being unsized.
|
||||
queue: (),
|
||||
}
|
||||
|
||||
|
@ -31,6 +36,8 @@ impl<T> Adapter for T {
|
|||
fn open() -> OpenDevice<Self::A>
|
||||
where
|
||||
<Self::A as Api>::Device: Sized,
|
||||
// ^ the bound expands to `<<T as Adapter>::A as Api>::Device: Sized`, which
|
||||
// is not considered trivial due to containing the type parameter `T`
|
||||
{
|
||||
unreachable!()
|
||||
}
|
16
tests/ui/methods/probe-error-on-infinite-deref.rs
Normal file
16
tests/ui/methods/probe-error-on-infinite-deref.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
// Make sure that method probe error reporting doesn't get too tangled up
|
||||
// on this infinite deref impl. See #130224.
|
||||
|
||||
struct Wrap<T>(T);
|
||||
impl<T> Deref for Wrap<T> {
|
||||
type Target = Wrap<Wrap<T>>;
|
||||
fn deref(&self) -> &Wrap<Wrap<T>> { todo!() }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Wrap(1).lmao();
|
||||
//~^ ERROR reached the recursion limit
|
||||
//~| ERROR no method named `lmao`
|
||||
}
|
21
tests/ui/methods/probe-error-on-infinite-deref.stderr
Normal file
21
tests/ui/methods/probe-error-on-infinite-deref.stderr
Normal file
|
@ -0,0 +1,21 @@
|
|||
error[E0055]: reached the recursion limit while auto-dereferencing `Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<{integer}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
|
||||
--> $DIR/probe-error-on-infinite-deref.rs:13:13
|
||||
|
|
||||
LL | Wrap(1).lmao();
|
||||
| ^^^^ deref recursion limit reached
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`probe_error_on_infinite_deref`)
|
||||
|
||||
error[E0599]: no method named `lmao` found for struct `Wrap<{integer}>` in the current scope
|
||||
--> $DIR/probe-error-on-infinite-deref.rs:13:13
|
||||
|
|
||||
LL | struct Wrap<T>(T);
|
||||
| -------------- method `lmao` not found for this struct
|
||||
...
|
||||
LL | Wrap(1).lmao();
|
||||
| ^^^^ method not found in `Wrap<{integer}>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0055, E0599.
|
||||
For more information about an error, try `rustc --explain E0055`.
|
|
@ -0,0 +1,12 @@
|
|||
#![feature(c_variadic)]
|
||||
|
||||
// Regression test that covers all 3 cases of https://github.com/rust-lang/rust/issues/130372
|
||||
|
||||
unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
test_va_copy();
|
||||
//~^ ERROR this function takes at least 1 argument but 0 arguments were supplied
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
error[E0060]: this function takes at least 1 argument but 0 arguments were supplied
|
||||
--> $DIR/mismatch-args-vargs-issue-130372.rs:9:9
|
||||
|
|
||||
LL | test_va_copy();
|
||||
| ^^^^^^^^^^^^-- argument #1 of type `u64` is missing
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/mismatch-args-vargs-issue-130372.rs:5:22
|
||||
|
|
||||
LL | unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {}
|
||||
| ^^^^^^^^^^^^ ------
|
||||
help: provide the argument
|
||||
|
|
||||
LL | test_va_copy(/* u64 */);
|
||||
| ~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0060`.
|
3
tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs
Normal file
3
tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub trait Foo {
|
||||
type Bar;
|
||||
}
|
11
tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs
Normal file
11
tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
//@ aux-build:foreign-trait-with-assoc.rs
|
||||
|
||||
extern crate foreign_trait_with_assoc;
|
||||
use foreign_trait_with_assoc::Foo;
|
||||
|
||||
// Make sure we don't try to call `fn_arg_names` on a non-fn item.
|
||||
|
||||
impl Foo for Bar {}
|
||||
//~^ ERROR cannot find type `Bar` in this scope
|
||||
|
||||
fn main() {}
|
14
tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr
Normal file
14
tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error[E0412]: cannot find type `Bar` in this scope
|
||||
--> $DIR/dont-compute-arg-names-for-non-fn.rs:8:14
|
||||
|
|
||||
LL | impl Foo for Bar {}
|
||||
| ^^^
|
||||
|
|
||||
help: you might have meant to use the associated type
|
||||
|
|
||||
LL | impl Foo for Self::Bar {}
|
||||
| ++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
Loading…
Add table
Reference in a new issue