diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 88a8d655d97a7..bf074fec66dd9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -13,7 +13,7 @@ use rustc_session::config::OptLevel; use tracing::{debug, instrument}; use super::place::{PlaceRef, PlaceValue}; -use super::rvalue::transmute_immediate; +use super::rvalue::transmute_scalar; use super::{FunctionCx, LocalRef}; use crate::common::IntPredicate; use crate::traits::*; @@ -346,14 +346,16 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let val = if field.is_zst() { OperandValue::ZeroSized + } else if let BackendRepr::SimdVector { .. } = self.layout.backend_repr { + // codegen_transmute_operand doesn't support SIMD, but since the previous + // check handled ZSTs, the only possible field access into something SIMD + // is to the `non_1zst_field` that's the same SIMD. (Other things, even + // just padding, would change the wrapper's representation type.) + assert_eq!(field.size, self.layout.size); + self.val } else if field.size == self.layout.size { assert_eq!(offset.bytes(), 0); - fx.codegen_transmute_operand(bx, *self, field).unwrap_or_else(|| { - bug!( - "Expected `codegen_transmute_operand` to handle equal-size \ - field {i:?} projection from {self:?} to {field:?}" - ) - }) + fx.codegen_transmute_operand(bx, *self, field) } else { let (in_scalar, imm) = match (self.val, self.layout.backend_repr) { // Extract a scalar component from a pair. @@ -613,10 +615,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result> { }; let mut update = |tgt: &mut Result, src, from_scalar| { - let from_bty = bx.cx().type_from_scalar(from_scalar); let to_scalar = tgt.unwrap_err(); - let to_bty = bx.cx().type_from_scalar(to_scalar); - let imm = transmute_immediate(bx, src, from_scalar, from_bty, to_scalar, to_bty); + let imm = transmute_scalar(bx, src, from_scalar, to_scalar); *tgt = Ok(imm); }; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index a8f9cbbe19b4a..43726e932520f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1,10 +1,8 @@ -use std::assert_matches::assert_matches; - use rustc_abi::{self as abi, FIRST_VARIANT}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_middle::{bug, mir, span_bug}; +use rustc_middle::{bug, mir}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; @@ -12,7 +10,7 @@ use tracing::{debug, instrument}; use super::operand::{OperandRef, OperandValue}; use super::place::{PlaceRef, codegen_tag_value}; use super::{FunctionCx, LocalRef}; -use crate::common::IntPredicate; +use crate::common::{IntPredicate, TypeKind}; use crate::traits::*; use crate::{MemFlags, base}; @@ -190,6 +188,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + /// Transmutes the `src` value to the destination type by writing it to `dst`. + /// + /// See also [`Self::codegen_transmute_operand`] for cases that can be done + /// without needing a pre-allocated place for the destination. fn codegen_transmute( &mut self, bx: &mut Bx, @@ -200,37 +202,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(src.layout.is_sized()); assert!(dst.layout.is_sized()); - if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) { - val.store(bx, dst); - return; - } - - match src.val { - OperandValue::Ref(..) | OperandValue::ZeroSized => { - span_bug!( - self.mir.span, - "Operand path should have handled transmute \ - from {src:?} to place {dst:?}" - ); - } - OperandValue::Immediate(..) | OperandValue::Pair(..) => { - // When we have immediate(s), the alignment of the source is irrelevant, - // so we can store them using the destination's alignment. - src.val.store(bx, dst.val.with_type(src.layout)); - } + if src.layout.size != dst.layout.size + || src.layout.is_uninhabited() + || dst.layout.is_uninhabited() + { + // These cases are all UB to actually hit, so don't emit code for them. + // (The size mismatches are reachable via `transmute_unchecked`.) + // We can't use unreachable because that's a terminator, and we + // need something that can be in the middle of a basic block. + bx.assume(bx.cx().const_bool(false)) + } else { + // Since in this path we have a place anyway, we can store or copy to it, + // making sure we use the destination place's alignment even if the + // source would normally have a higher one. + src.val.store(bx, dst.val.with_type(src.layout)); } } - /// Attempts to transmute an `OperandValue` to another `OperandValue`. + /// Transmutes an `OperandValue` to another `OperandValue`. /// - /// Returns `None` for cases that can't work in that framework, such as for - /// `Immediate`->`Ref` that needs an `alloc` to get the location. + /// This is supported only for cases where [`Self::rvalue_creates_operand`] + /// returns `true`, and will ICE otherwise. (In particular, anything that + /// would need to `alloca` in order to return a `PlaceValue` will ICE, + /// expecting those to go via [`Self::codegen_transmute`] instead where + /// the destination place is already allocated.) pub(crate) fn codegen_transmute_operand( &mut self, bx: &mut Bx, operand: OperandRef<'tcx, Bx::Value>, cast: TyAndLayout<'tcx>, - ) -> Option> { + ) -> OperandValue { // Check for transmutes that are always UB. if operand.layout.size != cast.size || operand.layout.is_uninhabited() @@ -244,71 +245,34 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Because this transmute is UB, return something easy to generate, // since it's fine that later uses of the value are probably UB. - return Some(OperandValue::poison(bx, cast)); + return OperandValue::poison(bx, cast); } - let operand_kind = self.value_kind(operand.layout); - let cast_kind = self.value_kind(cast); - - match operand.val { - OperandValue::Ref(source_place_val) => { + match (operand.val, operand.layout.backend_repr, cast.backend_repr) { + _ if cast.is_zst() => OperandValue::ZeroSized, + (_, _, abi::BackendRepr::Memory { .. }) => { + bug!("Cannot `codegen_transmute_operand` to non-ZST memory-ABI output {cast:?}"); + } + (OperandValue::Ref(source_place_val), abi::BackendRepr::Memory { .. }, _) => { assert_eq!(source_place_val.llextra, None); - assert_matches!(operand_kind, OperandValueKind::Ref); // The existing alignment is part of `source_place_val`, // so that alignment will be used, not `cast`'s. - Some(bx.load_operand(source_place_val.with_type(cast)).val) - } - OperandValue::ZeroSized => { - let OperandValueKind::ZeroSized = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::ZeroSized = cast_kind { - Some(OperandValue::ZeroSized) - } else { - None - } - } - OperandValue::Immediate(imm) => { - let OperandValueKind::Immediate(from_scalar) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::Immediate(to_scalar) = cast_kind - && from_scalar.size(self.cx) == to_scalar.size(self.cx) - { - let from_backend_ty = bx.backend_type(operand.layout); - let to_backend_ty = bx.backend_type(cast); - Some(OperandValue::Immediate(transmute_immediate( - bx, - imm, - from_scalar, - from_backend_ty, - to_scalar, - to_backend_ty, - ))) - } else { - None - } - } - OperandValue::Pair(imm_a, imm_b) => { - let OperandValueKind::Pair(in_a, in_b) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); - }; - if let OperandValueKind::Pair(out_a, out_b) = cast_kind - && in_a.size(self.cx) == out_a.size(self.cx) - && in_b.size(self.cx) == out_b.size(self.cx) - { - let in_a_ibty = bx.scalar_pair_element_backend_type(operand.layout, 0, false); - let in_b_ibty = bx.scalar_pair_element_backend_type(operand.layout, 1, false); - let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false); - let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false); - Some(OperandValue::Pair( - transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty), - transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty), - )) - } else { - None - } + bx.load_operand(source_place_val.with_type(cast)).val } + ( + OperandValue::Immediate(imm), + abi::BackendRepr::Scalar(from_scalar), + abi::BackendRepr::Scalar(to_scalar), + ) => OperandValue::Immediate(transmute_scalar(bx, imm, from_scalar, to_scalar)), + ( + OperandValue::Pair(imm_a, imm_b), + abi::BackendRepr::ScalarPair(in_a, in_b), + abi::BackendRepr::ScalarPair(out_a, out_b), + ) => OperandValue::Pair( + transmute_scalar(bx, imm_a, in_a, out_a), + transmute_scalar(bx, imm_b, in_b, out_b), + ), + _ => bug!("Cannot `codegen_transmute_operand` {operand:?} to {cast:?}"), } } @@ -479,9 +443,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // path as the other integer-to-X casts. | mir::CastKind::PointerWithExposedProvenance => { let imm = operand.immediate(); - let operand_kind = self.value_kind(operand.layout); - let OperandValueKind::Immediate(from_scalar) = operand_kind else { - bug!("Found {operand_kind:?} for operand {operand:?}"); + let abi::BackendRepr::Scalar(from_scalar) = operand.layout.backend_repr else { + bug!("Found non-scalar for operand {operand:?}"); }; let from_backend_ty = bx.cx().immediate_backend_type(operand.layout); @@ -491,9 +454,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty)); return OperandRef { val, layout: cast }; } - let cast_kind = self.value_kind(cast); - let OperandValueKind::Immediate(to_scalar) = cast_kind else { - bug!("Found {cast_kind:?} for operand {cast:?}"); + let abi::BackendRepr::Scalar(to_scalar) = cast.layout.backend_repr else { + bug!("Found non-scalar for cast {cast:?}"); }; self.cast_immediate(bx, imm, from_scalar, from_backend_ty, to_scalar, to_backend_ty) @@ -503,9 +465,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) } mir::CastKind::Transmute => { - self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| { - bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}"); - }) + self.codegen_transmute_operand(bx, operand, cast) } }; OperandRef { val, layout: cast } @@ -1011,37 +971,46 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Pair(val, of) } + /// Returns `true` if the `rvalue` can be computed into an [`OperandRef`], + /// rather than needing a full `PlaceRef` for the assignment destination. + /// + /// This is used by the [`super::analyze`] code to decide which MIR locals + /// can stay as SSA values (as opposed to generating `alloca` slots for them). + /// As such, some paths here return `true` even where the specific rvalue + /// will not actually take the operand path because the result type is such + /// that it always gets an `alloca`, but where it's not worth re-checking the + /// layout in this code when the right thing will happen anyway. pub(crate) fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { match *rvalue { mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => { let operand_ty = operand.ty(self.mir, self.cx.tcx()); let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty)); let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty)); + match (operand_layout.backend_repr, cast_layout.backend_repr) { + // When the output will be in memory anyway, just use its place + // (instead of the operand path) unless it's the trivial ZST case. + (_, abi::BackendRepr::Memory { .. }) => cast_layout.is_zst(), - match (self.value_kind(operand_layout), self.value_kind(cast_layout)) { - // Can always load from a pointer as needed - (OperandValueKind::Ref, _) => true, - - // ZST-to-ZST is the easiest thing ever - (OperandValueKind::ZeroSized, OperandValueKind::ZeroSized) => true, - - // But if only one of them is a ZST the sizes can't match - (OperandValueKind::ZeroSized, _) | (_, OperandValueKind::ZeroSized) => false, - - // Need to generate an `alloc` to get a pointer from an immediate - (OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false, + // Otherwise (for a non-memory output) if the input is memory + // then we can just read the value from the place. + (abi::BackendRepr::Memory { .. }, _) => true, // When we have scalar immediates, we can only convert things // where the sizes match, to avoid endianness questions. - (OperandValueKind::Immediate(a), OperandValueKind::Immediate(b)) => + (abi::BackendRepr::Scalar(a), abi::BackendRepr::Scalar(b)) => a.size(self.cx) == b.size(self.cx), - (OperandValueKind::Pair(a0, a1), OperandValueKind::Pair(b0, b1)) => + (abi::BackendRepr::ScalarPair(a0, a1), abi::BackendRepr::ScalarPair(b0, b1)) => a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx), - // Send mixings between scalars and pairs through the memory route - // FIXME: Maybe this could use insertvalue/extractvalue instead? - (OperandValueKind::Immediate(..), OperandValueKind::Pair(..)) | - (OperandValueKind::Pair(..), OperandValueKind::Immediate(..)) => false, + // Mixing Scalars and ScalarPairs can get quite complicated when + // padding and undef get involved, so leave that to the memory path. + (abi::BackendRepr::Scalar(_), abi::BackendRepr::ScalarPair(_, _)) | + (abi::BackendRepr::ScalarPair(_, _), abi::BackendRepr::Scalar(_)) => false, + + // SIMD vectors aren't worth the trouble of dealing with complex + // cases like from vectors of f32 to vectors of pointers or + // from fat pointers to vectors of u16. (See #143194 #110021 ...) + (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false, } } mir::Rvalue::Ref(..) | @@ -1071,68 +1040,43 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // (*) this is only true if the type is suitable } - - /// Gets which variant of [`OperandValue`] is expected for a particular type. - fn value_kind(&self, layout: TyAndLayout<'tcx>) -> OperandValueKind { - if layout.is_zst() { - OperandValueKind::ZeroSized - } else if self.cx.is_backend_immediate(layout) { - assert!(!self.cx.is_backend_scalar_pair(layout)); - OperandValueKind::Immediate(match layout.backend_repr { - abi::BackendRepr::Scalar(s) => s, - abi::BackendRepr::SimdVector { element, .. } => element, - x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), - }) - } else if self.cx.is_backend_scalar_pair(layout) { - let abi::BackendRepr::ScalarPair(s1, s2) = layout.backend_repr else { - span_bug!( - self.mir.span, - "Couldn't translate {:?} as backend scalar pair", - layout.backend_repr, - ); - }; - OperandValueKind::Pair(s1, s2) - } else { - OperandValueKind::Ref - } - } } -/// The variants of this match [`OperandValue`], giving details about the -/// backend values that will be held in that other type. -#[derive(Debug, Copy, Clone)] -enum OperandValueKind { - Ref, - Immediate(abi::Scalar), - Pair(abi::Scalar, abi::Scalar), - ZeroSized, -} - -/// Transmutes one of the immediates from an [`OperandValue::Immediate`] -/// or an [`OperandValue::Pair`] to an immediate of the target type. +/// Transmutes a single scalar value `imm` from `from_scalar` to `to_scalar`. +/// +/// This is expected to be in *immediate* form, as seen in [`OperandValue::Immediate`] +/// or [`OperandValue::Pair`] (so `i1` for bools, not `i8`, for example). /// -/// `to_backend_ty` must be the *non*-immediate backend type (so it will be -/// `i8`, not `i1`, for `bool`-like types.) -pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +/// ICEs if the passed-in `imm` is not a value of the expected type for +/// `from_scalar`, such as if it's a vector or a pair. +pub(super) fn transmute_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, mut imm: Bx::Value, from_scalar: abi::Scalar, - from_backend_ty: Bx::Type, to_scalar: abi::Scalar, - to_backend_ty: Bx::Type, ) -> Bx::Value { assert_eq!(from_scalar.size(bx.cx()), to_scalar.size(bx.cx())); + let imm_ty = bx.cx().val_ty(imm); + assert_ne!( + bx.cx().type_kind(imm_ty), + TypeKind::Vector, + "Vector type {imm_ty:?} not allowed in transmute_scalar {from_scalar:?} -> {to_scalar:?}" + ); // While optimizations will remove no-op transmutes, they might still be // there in debug or things that aren't no-op in MIR because they change // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar && from_backend_ty == to_backend_ty { + if from_scalar == to_scalar { return imm; } use abi::Primitive::*; imm = bx.from_immediate(imm); + let from_backend_ty = bx.cx().type_from_scalar(from_scalar); + debug_assert_eq!(bx.cx().val_ty(imm), from_backend_ty); + let to_backend_ty = bx.cx().type_from_scalar(to_scalar); + // If we have a scalar, we must already know its range. Either // // 1) It's a parameter with `range` parameter metadata, @@ -1163,6 +1107,8 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } }; + debug_assert_eq!(bx.cx().val_ty(imm), to_backend_ty); + // This `assume` remains important for cases like (a conceptual) // transmute::(x) == 0 // since it's never passed to something with parameter metadata (especially diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 7ffde233da342..e53c128efe069 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -627,7 +627,7 @@ macro_rules! rem_impl_float { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ops", issue = "90080")] - impl Rem for $t { + impl const Rem for $t { type Output = $t; #[inline] diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index cc1d0b30152a1..571f0d14248e1 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -13,7 +13,7 @@ //! depend on the primitive. See [#Overview] bellow. //! //! For the alternative implementations that do not employ poisoning, -//! see `std::sys::nonpoisoning`. +//! see `std::sync::nonpoisoning`. //! //! # Overview //! diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index b3104ae05e884..b2293fdd9b523 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -5,6 +5,8 @@ use std::path::PathBuf; +use clap_complete::{Generator, shells}; + use crate::core::build_steps::dist::distdir; use crate::core::build_steps::test; use crate::core::build_steps::tool::{self, SourceType, Tool}; @@ -285,36 +287,35 @@ impl Step for GenerateWindowsSys { } } +/// Return tuples of (shell, file containing completions). +pub fn get_completion_paths(builder: &Builder<'_>) -> Vec<(&'static dyn Generator, PathBuf)> { + vec![ + (&shells::Bash as &'static dyn Generator, builder.src.join("src/etc/completions/x.py.sh")), + (&shells::Zsh, builder.src.join("src/etc/completions/x.py.zsh")), + (&shells::Fish, builder.src.join("src/etc/completions/x.py.fish")), + (&shells::PowerShell, builder.src.join("src/etc/completions/x.py.ps1")), + (&shells::Bash, builder.src.join("src/etc/completions/x.sh")), + (&shells::Zsh, builder.src.join("src/etc/completions/x.zsh")), + (&shells::Fish, builder.src.join("src/etc/completions/x.fish")), + (&shells::PowerShell, builder.src.join("src/etc/completions/x.ps1")), + ] +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenerateCompletions; -macro_rules! generate_completions { - ( $( ( $shell:ident, $filename:expr ) ),* ) => { - $( - if let Some(comp) = get_completion($shell, &$filename) { - std::fs::write(&$filename, comp).expect(&format!("writing {} completion", stringify!($shell))); - } - )* - }; -} - impl Step for GenerateCompletions { type Output = (); /// Uses `clap_complete` to generate shell completions. fn run(self, builder: &Builder<'_>) { - use clap_complete::shells::{Bash, Fish, PowerShell, Zsh}; - - generate_completions!( - (Bash, builder.src.join("src/etc/completions/x.py.sh")), - (Zsh, builder.src.join("src/etc/completions/x.py.zsh")), - (Fish, builder.src.join("src/etc/completions/x.py.fish")), - (PowerShell, builder.src.join("src/etc/completions/x.py.ps1")), - (Bash, builder.src.join("src/etc/completions/x.sh")), - (Zsh, builder.src.join("src/etc/completions/x.zsh")), - (Fish, builder.src.join("src/etc/completions/x.fish")), - (PowerShell, builder.src.join("src/etc/completions/x.ps1")) - ); + for (shell, path) in get_completion_paths(builder) { + if let Some(comp) = get_completion(shell, &path) { + std::fs::write(&path, comp).unwrap_or_else(|e| { + panic!("writing completion into {} failed: {e:?}", path.display()) + }); + } + } } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 2d4d9e535981c..a5b7b22aba85f 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -8,12 +8,11 @@ use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::{env, fs, iter}; -use clap_complete::shells; - use crate::core::build_steps::compile::{Std, run_cargo}; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; +use crate::core::build_steps::run::get_completion_paths; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool}; use crate::core::build_steps::toolstate::ToolState; @@ -1153,14 +1152,12 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to cmd.delay_failure().run(builder); builder.info("x.py completions check"); - let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] - .map(|filename| builder.src.join("src/etc/completions").join(filename)); + let completion_paths = get_completion_paths(builder); if builder.config.cmd.bless() { builder.ensure(crate::core::build_steps::run::GenerateCompletions); - } else if get_completion(shells::Bash, &bash).is_some() - || get_completion(shells::Fish, &fish).is_some() - || get_completion(shells::PowerShell, &powershell).is_some() - || crate::flags::get_completion(shells::Zsh, &zsh).is_some() + } else if completion_paths + .into_iter() + .any(|(shell, path)| get_completion(shell, &path).is_some()) { eprintln!( "x.py completions were changed; run `x.py run generate-completions` to update them" diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 79275db648631..bfc06f90d4f26 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use clap::{CommandFactory, Parser, ValueEnum}; +use clap_complete::Generator; #[cfg(feature = "tracing")] use tracing::instrument; @@ -644,7 +645,7 @@ impl Subcommand { /// Returns the shell completion for a given shell, if the result differs from the current /// content of `path`. If `path` does not exist, always returns `Some`. -pub fn get_completion(shell: G, path: &Path) -> Option { +pub fn get_completion(shell: &dyn Generator, path: &Path) -> Option { let mut cmd = Flags::command(); let current = if !path.exists() { String::new() @@ -662,7 +663,12 @@ pub fn get_completion(shell: G, path: &Path) -> Opt .expect("file name should be UTF-8") .rsplit_once('.') .expect("file name should have an extension"); - clap_complete::generate(shell, &mut cmd, bin_name, &mut buf); + + // We sort of replicate `clap_complete::generate` here, because we want to call it with + // `&dyn Generator`, but that function requires `G: Generator` instead. + cmd.set_bin_name(bin_name); + cmd.build(); + shell.generate(&cmd, &mut buf); if buf == current.as_bytes() { return None; } diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 46d18ac7dbcbc..69bd525a31221 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -293,7 +293,7 @@ complete -c x -n "__fish_x_using_subcommand doc" -l skip-std-check-if-no-downloa complete -c x -n "__fish_x_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x -n "__fish_x_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r -complete -c x -n "__fish_x_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r +complete -c x -n "__fish_x_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)' -r complete -c x -n "__fish_x_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index 1ca00bb67dfed..7b142ba97ce51 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -339,7 +339,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;test' { [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)') [CompletionResult]::new('--compiletest-rustc-args', '--compiletest-rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running compiletest tests') - [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)') + [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)') [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 00fb7d8e2ecbd..c495e8318ba46 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -338,7 +338,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \ '*--compiletest-rustc-args=[extra options to pass the compiler when running compiletest tests]:ARGS:_default' \ -'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS:_default' \ +'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell, shell\:lint, cpp, cpp\:fmt, spellcheck, spellcheck\:fix)]:EXTRA_CHECKS:_default' \ '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \ '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 49b4287e4e337..cac4dba2b49d7 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -276,7 +276,6 @@ ui/auto-traits/issue-23080-2.rs ui/auto-traits/issue-23080.rs ui/auto-traits/issue-83857-ub.rs ui/auto-traits/issue-84075.rs -ui/auxiliary/issue-16822.rs ui/bench/issue-32062.rs ui/binding/issue-40402-1.rs ui/binding/issue-40402-2.rs @@ -1367,9 +1366,6 @@ ui/infinite/issue-41731-infinite-macro-println.rs ui/intrinsics/issue-28575.rs ui/intrinsics/issue-84297-reifying-copy.rs ui/invalid/issue-114435-layout-type-err.rs -ui/issue-15924.rs -ui/issue-16822.rs -ui/issues-71798.rs ui/issues/auxiliary/issue-11224.rs ui/issues/auxiliary/issue-11508.rs ui/issues/auxiliary/issue-11529.rs diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs index be45e4db90fd9..8c9480ab0915e 100644 --- a/tests/codegen/intrinsics/transmute-x64.rs +++ b/tests/codegen/intrinsics/transmute-x64.rs @@ -9,17 +9,20 @@ use std::mem::transmute; // CHECK-LABEL: @check_sse_pair_to_avx( #[no_mangle] pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { + // CHECK: start: // CHECK-NOT: alloca - // CHECK: %0 = load <4 x i64>, ptr %x, align 16 - // CHECK: store <4 x i64> %0, ptr %_0, align 32 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 32 %_0, ptr align 16 %x, i64 32, i1 false) + // CHECK-NEXT: ret void transmute(x) } // CHECK-LABEL: @check_sse_pair_from_avx( #[no_mangle] pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) { + // CHECK: start: // CHECK-NOT: alloca - // CHECK: %0 = load <4 x i64>, ptr %x, align 32 - // CHECK: store <4 x i64> %0, ptr %_0, align 16 + // CHECK-NEXT: %[[TEMP:.+]] = load <4 x i64>, ptr %x, align 32 + // CHECK-NEXT: store <4 x i64> %[[TEMP]], ptr %_0, align 16 + // CHECK-NEXT: ret void transmute(x) } diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 560ebcccdd021..e375724bc1bbd 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -29,28 +29,28 @@ pub struct Aggregate8(u8); // CHECK-LABEL: @check_bigger_size( #[no_mangle] pub unsafe fn check_bigger_size(x: u16) -> u32 { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_size( #[no_mangle] pub unsafe fn check_smaller_size(x: u32) -> u16 { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_array( #[no_mangle] pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } // CHECK-LABEL: @check_bigger_array( #[no_mangle] pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { - // CHECK: call void @llvm.trap + // CHECK: call void @llvm.assume(i1 false) transmute_unchecked(x) } @@ -73,9 +73,9 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { { RET = CastTransmute(x); diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index 977bf3379b7dd..301f06c2d74ae 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -40,8 +40,7 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> { // CHECK-LABEL: @build_array_transmute_s #[no_mangle] pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { - // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) unsafe { std::mem::transmute(x) } } @@ -55,7 +54,6 @@ pub fn build_array_t(x: [f32; 4]) -> T { // CHECK-LABEL: @build_array_transmute_t #[no_mangle] pub fn build_array_transmute_t(x: [f32; 4]) -> T { - // CHECK: %[[VAL:.+]] = load <4 x float>, ptr %x, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], ptr %_0, align [[VECTOR_ALIGN]] + // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false) unsafe { std::mem::transmute(x) } } diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 3ac6ba3beb1ee..ce1b0558b2eec 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -111,8 +111,11 @@ pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { struct S([i64; 1]); // CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b) -// CHECK: bitcast <1 x i64> %b to i64 -// CHECK: ret i64 +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store <1 x i64> %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load i64, ptr %[[RET]] +// CHECK-NEXT: ret i64 %[[TEMP]] #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] @@ -124,8 +127,11 @@ pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 { } // CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b) -// CHECK: bitcast i64 %b to <1 x i64> -// CHECK: ret <1 x i64> +// CHECK-NEXT: start: +// CHECK-NEXT: %[[RET:.+]] = alloca [8 x i8] +// CHECK-NEXT: store i64 %b, ptr %[[RET]] +// CHECK-NEXT: %[[TEMP:.+]] = load <1 x i64>, ptr %[[RET]] +// CHECK-NEXT: ret <1 x i64> %[[TEMP]] #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index 1f6836f6dfabb..a5ef8653b997e 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -41,9 +41,6 @@ pub fn vec_iterator_cast_primitive(vec: Vec) -> Vec { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| e as u8).collect() } @@ -55,9 +52,6 @@ pub fn vec_iterator_cast_wrapper(vec: Vec) -> Vec> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| Wrapper(e)).collect() } @@ -86,9 +80,6 @@ pub fn vec_iterator_cast_unwrap(vec: Vec>) -> Vec { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| e.0).collect() } @@ -100,9 +91,6 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() } @@ -114,9 +102,6 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec) -> Vec<[u64; 4]> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. // This currently is not guaranteed for repr(Rust) types, but it happens to work here and @@ -133,9 +118,6 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec) -> Vec<[u64; 4]> { // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call - // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: loop - // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. // This currently is not guaranteed for repr(Rust) types, but it happens to work here and @@ -156,12 +138,7 @@ pub fn vec_iterator_cast_unwrap_drop(vec: Vec>) -> Vec { // CHECK-NOT: call // CHECK-NOT: %{{.*}} = mul // CHECK-NOT: %{{.*}} = udiv - // CHECK: call - // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: call - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv + // CHECK: ret void vec.into_iter().map(|Wrapper(e)| e).collect() } @@ -178,12 +155,6 @@ pub fn vec_iterator_cast_wrap_drop(vec: Vec) -> Vec> { // CHECK-NOT: call // CHECK-NOT: %{{.*}} = mul // CHECK-NOT: %{{.*}} = udiv - // CHECK: call - // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) - // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} - // CHECK-NOT: call - // CHECK-NOT: %{{.*}} = mul - // CHECK-NOT: %{{.*}} = udiv // CHECK: ret void vec.into_iter().map(Wrapper).collect() diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs index 36c9db106ec45..63d8d713d6226 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs @@ -1,7 +1,8 @@ #![crate_type = "staticlib"] #![feature(c_variadic)] +#![feature(cfg_select)] -use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong}; +use std::ffi::{CStr, CString, VaList, VaListImpl, c_char, c_double, c_int, c_long, c_longlong}; macro_rules! continue_if { ($cond:expr) => { @@ -19,7 +20,7 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize { continue_if!(ap.arg::() == 1); continue_if!(ap.arg::() == 2); @@ -27,7 +28,7 @@ pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { continue_if!(ap.arg::() == -1); continue_if!(ap.arg::() == 'A' as c_int); @@ -39,7 +40,7 @@ pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); @@ -51,7 +52,7 @@ pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 6.28f64.floor()); continue_if!(ap.arg::() == 16); @@ -64,14 +65,14 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { ) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 42); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!")); 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); @@ -80,12 +81,12 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1); continue_if!(ap.arg::() == 2); @@ -100,7 +101,7 @@ pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1.0); continue_if!(ap.arg::() == 2.0); @@ -118,7 +119,7 @@ pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1.0); continue_if!(ap.arg::() == 1); @@ -148,3 +149,42 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 13.0); 0 } + +unsafe extern "C" { + fn test_variadic(_: c_int, ...) -> usize; + fn test_va_list_by_value(_: VaList) -> usize; + fn test_va_list_by_pointer(_: *mut VaListImpl) -> usize; + fn test_va_list_by_pointer_pointer(_: *mut *mut VaListImpl) -> usize; +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_variadic() -> usize { + return unsafe { test_variadic(0, 1 as c_longlong, 2 as c_int, 3 as c_longlong) }; +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_value() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_value(ap.as_va_list()) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_pointer() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_pointer(&mut ap) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_pointer_pointer() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_pointer_pointer(&mut (&mut ap as *mut _)) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} diff --git a/tests/run-make/c-link-to-rust-va-list-fn/test.c b/tests/run-make/c-link-to-rust-va-list-fn/test.c index b47a9357880f1..2bb93c0b5d0ef 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/test.c +++ b/tests/run-make/c-link-to-rust-va-list-fn/test.c @@ -15,6 +15,11 @@ extern size_t check_varargs_3(int fixed, ...); extern size_t check_varargs_4(double fixed, ...); extern size_t check_varargs_5(int fixed, ...); +extern size_t run_test_variadic(); +extern size_t run_test_va_list_by_value(); +extern size_t run_test_va_list_by_pointer(); +extern size_t run_test_va_list_by_pointer_pointer(); + int test_rust(size_t (*fn)(va_list), ...) { size_t ret = 0; va_list ap; @@ -47,5 +52,53 @@ int main(int argc, char* argv[]) { assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0, 9, 9.0, 10, 10.0, 11, 11.0, 12, 12.0, 13, 13.0) == 0); + assert(run_test_variadic() == 0); + assert(run_test_va_list_by_value() == 0); + assert(run_test_va_list_by_pointer() == 0); + assert(run_test_va_list_by_pointer_pointer() == 0); + + return 0; +} + +#define continue_if_else_end(cond) \ + do { if (!(cond)) { va_end(ap); return 0xff; } } while (0) + +size_t test_variadic(int unused, ...) { + va_list ap; + va_start(ap, unused); + + continue_if_else_end(va_arg(ap, long long) == 1); + continue_if_else_end(va_arg(ap, int) == 2); + continue_if_else_end(va_arg(ap, long long) == 3); + + va_end(ap); + + return 0; +} + +#define continue_if(cond) \ + do { if (!(cond)) { return 0xff; } } while (0) + +size_t test_va_list_by_value(va_list ap) { + continue_if(va_arg(ap, long long) == 1); + continue_if(va_arg(ap, int) == 2); + continue_if(va_arg(ap, long long) == 3); + + return 0; +} + +size_t test_va_list_by_pointer(va_list *ap) { + continue_if(va_arg(*ap, long long) == 1); + continue_if(va_arg(*ap, int) == 2); + continue_if(va_arg(*ap, long long) == 3); + + return 0; +} + +size_t test_va_list_by_pointer_pointer(va_list **ap) { + continue_if(va_arg(**ap, long long) == 1); + continue_if(va_arg(**ap, int) == 2); + continue_if(va_arg(**ap, long long) == 3); + return 0; } diff --git a/tests/ui/realloc-16687.rs b/tests/ui/allocator/alloc-shrink-oob-read.rs similarity index 96% rename from tests/ui/realloc-16687.rs rename to tests/ui/allocator/alloc-shrink-oob-read.rs index 43810a469dfec..b9edfca3b7b51 100644 --- a/tests/ui/realloc-16687.rs +++ b/tests/ui/allocator/alloc-shrink-oob-read.rs @@ -1,13 +1,13 @@ +//! Sanity check for out-of-bounds read caused by copying the entire original buffer on shrink. +//! +//! Regression test for: + //@ run-pass -// alloc::heap::reallocate test. -// -// Ideally this would be revised to use no_std, but for now it serves -// well enough to reproduce (and illustrate) the bug from #16687. #![feature(allocator_api)] #![feature(slice_ptr_get)] -use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; +use std::alloc::{Allocator, Global, Layout, handle_alloc_error}; use std::ptr::{self, NonNull}; fn main() { diff --git a/tests/ui/issues-71798.rs b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs similarity index 51% rename from tests/ui/issues-71798.rs rename to tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs index 14b6c0f35812f..ea30e8c839f77 100644 --- a/tests/ui/issues-71798.rs +++ b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.rs @@ -1,3 +1,7 @@ +//! Regression test for issue https://github.com/rust-lang/rust/issues/71798 +// ICE with escaping bound variables when impl Future + '_ +// returns non-Future type combined with syntax errors + fn test_ref(x: &u32) -> impl std::future::Future + '_ { //~^ ERROR `u32` is not a future *x diff --git a/tests/ui/issues-71798.stderr b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr similarity index 85% rename from tests/ui/issues-71798.stderr rename to tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr index 52dd14ccb0a14..5beca58e13c77 100644 --- a/tests/ui/issues-71798.stderr +++ b/tests/ui/async-await/impl-future-escaping-bound-vars-ice.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find value `u` in this scope - --> $DIR/issues-71798.rs:7:24 + --> $DIR/impl-future-escaping-bound-vars-ice.rs:11:24 | LL | let _ = test_ref & u; | ^ not found in this scope error[E0277]: `u32` is not a future - --> $DIR/issues-71798.rs:1:25 + --> $DIR/impl-future-escaping-bound-vars-ice.rs:5:25 | LL | fn test_ref(x: &u32) -> impl std::future::Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future diff --git a/tests/ui/reexport-test-harness-main.rs b/tests/ui/attributes/reexport-test-harness-entry-point.rs similarity index 59% rename from tests/ui/reexport-test-harness-main.rs rename to tests/ui/attributes/reexport-test-harness-entry-point.rs index f79828fc7d666..95765a719ed58 100644 --- a/tests/ui/reexport-test-harness-main.rs +++ b/tests/ui/attributes/reexport-test-harness-entry-point.rs @@ -1,3 +1,6 @@ +//! Check that `#[reexport_test_harness_main]` correctly reexports the test harness entry point +//! and allows it to be called from within the code. + //@ run-pass //@ compile-flags:--test diff --git a/tests/ui/phantom-auto-trait.rs b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs similarity index 68% rename from tests/ui/phantom-auto-trait.rs rename to tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs index 0172ca335c32a..6d1c4c87fad47 100644 --- a/tests/ui/phantom-auto-trait.rs +++ b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.rs @@ -1,9 +1,9 @@ -// Ensure that auto trait checks `T` when it encounters a `PhantomData` field, instead of -// checking the `PhantomData` type itself (which almost always implements an auto trait). +//! Ensure that auto trait checks `T` when it encounters a `PhantomData` field, instead of +//! checking the `PhantomData` type itself (which almost always implements an auto trait). #![feature(auto_traits)] -use std::marker::{PhantomData}; +use std::marker::PhantomData; unsafe auto trait Zen {} diff --git a/tests/ui/phantom-auto-trait.stderr b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr similarity index 82% rename from tests/ui/phantom-auto-trait.stderr rename to tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr index ffd4c3a0e1ad0..56c2e8ff257b7 100644 --- a/tests/ui/phantom-auto-trait.stderr +++ b/tests/ui/auto-traits/auto-trait-phantom-data-bounds.stderr @@ -1,5 +1,5 @@ error[E0277]: `T` cannot be shared between threads safely - --> $DIR/phantom-auto-trait.rs:21:12 + --> $DIR/auto-trait-phantom-data-bounds.rs:21:12 | LL | is_zen(x) | ------ ^ `T` cannot be shared between threads safely @@ -7,19 +7,19 @@ LL | is_zen(x) | required by a bound introduced by this call | note: required for `&T` to implement `Zen` - --> $DIR/phantom-auto-trait.rs:10:24 + --> $DIR/auto-trait-phantom-data-bounds.rs:10:24 | LL | unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {} | ^^^ ^^^^^ ---- unsatisfied trait bound introduced here note: required because it appears within the type `PhantomData<&T>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `Guard<'_, T>` - --> $DIR/phantom-auto-trait.rs:12:8 + --> $DIR/auto-trait-phantom-data-bounds.rs:12:8 | LL | struct Guard<'a, T: 'a> { | ^^^^^ note: required by a bound in `is_zen` - --> $DIR/phantom-auto-trait.rs:18:14 + --> $DIR/auto-trait-phantom-data-bounds.rs:18:14 | LL | fn is_zen(_: T) {} | ^^^ required by this bound in `is_zen` @@ -29,7 +29,7 @@ LL | fn not_sync(x: Guard) { | +++++++++++++++++++ error[E0277]: `T` cannot be shared between threads safely - --> $DIR/phantom-auto-trait.rs:26:12 + --> $DIR/auto-trait-phantom-data-bounds.rs:26:12 | LL | is_zen(x) | ------ ^ `T` cannot be shared between threads safely @@ -37,24 +37,24 @@ LL | is_zen(x) | required by a bound introduced by this call | note: required for `&T` to implement `Zen` - --> $DIR/phantom-auto-trait.rs:10:24 + --> $DIR/auto-trait-phantom-data-bounds.rs:10:24 | LL | unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {} | ^^^ ^^^^^ ---- unsatisfied trait bound introduced here note: required because it appears within the type `PhantomData<&T>` --> $SRC_DIR/core/src/marker.rs:LL:COL note: required because it appears within the type `Guard<'_, T>` - --> $DIR/phantom-auto-trait.rs:12:8 + --> $DIR/auto-trait-phantom-data-bounds.rs:12:8 | LL | struct Guard<'a, T: 'a> { | ^^^^^ note: required because it appears within the type `Nested>` - --> $DIR/phantom-auto-trait.rs:16:8 + --> $DIR/auto-trait-phantom-data-bounds.rs:16:8 | LL | struct Nested(T); | ^^^^^^ note: required by a bound in `is_zen` - --> $DIR/phantom-auto-trait.rs:18:14 + --> $DIR/auto-trait-phantom-data-bounds.rs:18:14 | LL | fn is_zen(_: T) {} | ^^^ required by this bound in `is_zen` diff --git a/tests/ui/binop/binop-evaluation-order-primitive.rs b/tests/ui/binop/binop-evaluation-order-primitive.rs new file mode 100644 index 0000000000000..33266d1c0478a --- /dev/null +++ b/tests/ui/binop/binop-evaluation-order-primitive.rs @@ -0,0 +1,15 @@ +//! Test evaluation order in binary operations with primitive types. + +//@ run-pass + +fn main() { + let x = Box::new(0); + assert_eq!( + 0, + *x + { + drop(x); + let _ = Box::new(main); + 0 + } + ); +} diff --git a/tests/ui/op-assign-builtins-by-ref.rs b/tests/ui/binop/compound-assign-by-ref.rs similarity index 90% rename from tests/ui/op-assign-builtins-by-ref.rs rename to tests/ui/binop/compound-assign-by-ref.rs index 73788da92321c..e1f519a137fc9 100644 --- a/tests/ui/op-assign-builtins-by-ref.rs +++ b/tests/ui/binop/compound-assign-by-ref.rs @@ -1,9 +1,8 @@ +//! Test compound assignment operators with reference right-hand side. + //@ run-pass fn main() { - // test compound assignment operators with ref as right-hand side, - // for each operator, with various types as operands. - // test AddAssign { let mut x = 3i8; diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs new file mode 100644 index 0000000000000..7618e83a64290 --- /dev/null +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs @@ -0,0 +1,18 @@ +//! Test that nested `cfg_attr` attributes work correctly for conditional compilation. +//! This checks that `cfg_attr` can be arbitrarily deeply nested and that the +//! expansion works from outside to inside, eventually applying the innermost +//! conditional compilation directive. +//! +//! In this test, `cfg_attr(all(), cfg_attr(all(), cfg(false)))` should expand to: +//! 1. `cfg_attr(all(), cfg(false))` (outer cfg_attr applied) +//! 2. `cfg(false)` (inner cfg_attr applied) +//! 3. Function `f` is excluded from compilation +//! +//! Added in . + +#[cfg_attr(all(), cfg_attr(all(), cfg(false)))] +fn f() {} + +fn main() { + f() //~ ERROR cannot find function `f` in this scope +} diff --git a/tests/ui/nested-cfg-attrs.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr similarity index 61% rename from tests/ui/nested-cfg-attrs.stderr rename to tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr index 16c2930714353..ddb8ea1e13ae5 100644 --- a/tests/ui/nested-cfg-attrs.stderr +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr @@ -1,8 +1,8 @@ error[E0425]: cannot find function `f` in this scope - --> $DIR/nested-cfg-attrs.rs:4:13 + --> $DIR/nested-cfg-attr-conditional-compilation.rs:17:5 | -LL | fn main() { f() } - | ^ not found in this scope +LL | f() + | ^ not found in this scope error: aborting due to 1 previous error diff --git a/tests/ui/closures/closure-capture-after-clone.rs b/tests/ui/closures/closure-capture-after-clone.rs new file mode 100644 index 0000000000000..29fba147909b4 --- /dev/null +++ b/tests/ui/closures/closure-capture-after-clone.rs @@ -0,0 +1,39 @@ +//! Regression test for issue #1399 +//! +//! This tests that when a variable is used (via clone) and then later +//! captured by a closure, the last-use analysis doesn't incorrectly optimize +//! the earlier use as a "last use" and perform an invalid move. +//! +//! The sequence being tested: +//! 1. Create variable `k` +//! 2. Use `k.clone()` for some purpose +//! 3. Later capture `k` in a closure +//! +//! The analysis must not treat step 2 as the "last use" since step 3 needs `k`. +//! +//! See: https://github.com/rust-lang/rust/issues/1399 + +//@ run-pass + +struct A { + _a: Box, +} + +pub fn main() { + fn invoke(f: F) + where + F: FnOnce(), + { + f(); + } + + let k: Box<_> = 22.into(); + + // This clone should NOT be treated as "last use" of k + // even though k is not used again until the closure + let _u = A { _a: k.clone() }; + + // Here k is actually captured by the closure + // The last-use analyzer must have accounted for this when processing the clone above + invoke(|| println!("{}", k.clone())); +} diff --git a/tests/ui/closures/closure-last-use-move.rs b/tests/ui/closures/closure-last-use-move.rs new file mode 100644 index 0000000000000..f5b99d87f0918 --- /dev/null +++ b/tests/ui/closures/closure-last-use-move.rs @@ -0,0 +1,33 @@ +//! Regression test for issue #1818 +//! last-use analysis in closures should allow moves instead of requiring copies. +//! +//! The original issue was that the compiler incorrectly flagged certain return values +//! in anonymous functions/closures as requiring copies of non-copyable values, when +//! they should have been treated as moves (since they were the last use of the value). +//! +//! See: https://github.com/rust-lang/rust/issues/1818 + +//@ run-pass + +fn apply(s: String, mut f: F) -> T +where + F: FnMut(String) -> T +{ + fn g(s: String, mut f: F) -> T + where + F: FnMut(String) -> T + { + f(s) + } + + g(s, |v| { + let r = f(v); + r // This should be a move, not requiring copy + }) +} + +pub fn main() { + // Actually test the functionality + let result = apply(String::from("test"), |s| s.len()); + assert_eq!(result, 4); +} diff --git a/tests/ui/not-copy-closure.rs b/tests/ui/closures/closure-no-copy-mut-env.rs similarity index 65% rename from tests/ui/not-copy-closure.rs rename to tests/ui/closures/closure-no-copy-mut-env.rs index f6530f9a410aa..890e99c1ac79c 100644 --- a/tests/ui/not-copy-closure.rs +++ b/tests/ui/closures/closure-no-copy-mut-env.rs @@ -1,4 +1,4 @@ -// Check that closures do not implement `Copy` if their environment is not `Copy`. +//! Checks that closures do not implement `Copy` when they capture mutable references. fn main() { let mut a = 5; diff --git a/tests/ui/not-copy-closure.stderr b/tests/ui/closures/closure-no-copy-mut-env.stderr similarity index 84% rename from tests/ui/not-copy-closure.stderr rename to tests/ui/closures/closure-no-copy-mut-env.stderr index 60cb135231306..1443366a47700 100644 --- a/tests/ui/not-copy-closure.stderr +++ b/tests/ui/closures/closure-no-copy-mut-env.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `hello` - --> $DIR/not-copy-closure.rs:10:13 + --> $DIR/closure-no-copy-mut-env.rs:10:13 | LL | let b = hello; | ----- value moved here @@ -7,7 +7,7 @@ LL | let c = hello; | ^^^^^ value used here after move | note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment - --> $DIR/not-copy-closure.rs:6:9 + --> $DIR/closure-no-copy-mut-env.rs:6:9 | LL | a += 1; | ^ diff --git a/tests/ui/closures/closure-upvar-last-use-analysis.rs b/tests/ui/closures/closure-upvar-last-use-analysis.rs new file mode 100644 index 0000000000000..2c3e349437dc1 --- /dev/null +++ b/tests/ui/closures/closure-upvar-last-use-analysis.rs @@ -0,0 +1,32 @@ +//! Regression test for issue #1399 +//! +//! This tests that the compiler's last-use analysis correctly handles variables +//! that are captured by closures (upvars). The original issue was that the analysis +//! would incorrectly optimize variable usage as "last use" and perform moves, even when +//! the variable was later needed by a closure that captured it. +//! +//! See: https://github.com/rust-lang/rust/issues/1399 + +//@ run-pass + +struct A { + _a: Box, +} + +fn foo() -> Box isize + 'static> { + let k: Box<_> = Box::new(22); + + // This use of k.clone() should not be treated as a "last use" + // even though the closure below doesn't actually capture k + let _u = A { _a: k.clone() }; + + // The closure doesn't actually use k, but the analyzer needs to handle + // the potential capture scenario correctly + let result = || 22; + + Box::new(result) +} + +pub fn main() { + assert_eq!(foo()(), 22); +} diff --git a/tests/ui/once-cant-call-twice-on-heap.rs b/tests/ui/closures/fnonce-call-twice-error.rs similarity index 53% rename from tests/ui/once-cant-call-twice-on-heap.rs rename to tests/ui/closures/fnonce-call-twice-error.rs index 3fd8c5cadca98..1662b7bddaaee 100644 --- a/tests/ui/once-cant-call-twice-on-heap.rs +++ b/tests/ui/closures/fnonce-call-twice-error.rs @@ -1,16 +1,15 @@ -// Testing guarantees provided by once functions. -// This program would segfault if it were legal. +//! Test that `FnOnce` closures cannot be called twice. use std::sync::Arc; -fn foo(blk: F) { +fn foo(blk: F) { blk(); blk(); //~ ERROR use of moved value } fn main() { let x = Arc::new(true); - foo(move|| { + foo(move || { assert!(*x); drop(x); }); diff --git a/tests/ui/once-cant-call-twice-on-heap.stderr b/tests/ui/closures/fnonce-call-twice-error.stderr similarity index 56% rename from tests/ui/once-cant-call-twice-on-heap.stderr rename to tests/ui/closures/fnonce-call-twice-error.stderr index 42697374115ca..51d8a33dcd796 100644 --- a/tests/ui/once-cant-call-twice-on-heap.stderr +++ b/tests/ui/closures/fnonce-call-twice-error.stderr @@ -1,18 +1,18 @@ error[E0382]: use of moved value: `blk` - --> $DIR/once-cant-call-twice-on-heap.rs:8:5 + --> $DIR/fnonce-call-twice-error.rs:7:5 | -LL | fn foo(blk: F) { - | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait +LL | fn foo(blk: F) { + | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait LL | blk(); | ----- `blk` moved due to this call LL | blk(); | ^^^ value used here after move | note: `FnOnce` closures can only be called once - --> $DIR/once-cant-call-twice-on-heap.rs:6:10 + --> $DIR/fnonce-call-twice-error.rs:5:11 | -LL | fn foo(blk: F) { - | ^^^^^^^^ `F` is made to be an `FnOnce` closure here +LL | fn foo(blk: F) { + | ^^^^^^^^ `F` is made to be an `FnOnce` closure here LL | blk(); | ----- this value implements `FnOnce`, which causes it to be moved when called diff --git a/tests/ui/closures/many-closures.rs b/tests/ui/closures/many-closures.rs new file mode 100644 index 0000000000000..c96ef5544c22e --- /dev/null +++ b/tests/ui/closures/many-closures.rs @@ -0,0 +1,47 @@ +//! Test that the compiler can handle code bases with a high number of closures. +//! This is particularly important for the MinGW toolchain which has a limit of +//! 2^15 weak symbols per binary. This test creates 2^12 closures (256 functions +//! with 16 closures each) to check the compiler handles this correctly. +//! +//! Regression test for . +//! See also . + +//@ run-pass + +// Make sure we don't optimize anything away: +//@ compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals + +/// Macro for exponential expansion - creates 2^n copies of the given macro call +macro_rules! go_bacterial { + ($mac:ident) => ($mac!()); + ($mac:ident 1 $($t:tt)*) => ( + go_bacterial!($mac $($t)*); + go_bacterial!($mac $($t)*); + ) +} + +/// Creates and immediately calls a closure +macro_rules! create_closure { + () => { + (move || {})() + }; +} + +/// Creates a function containing 16 closures (2^4) +macro_rules! create_function_with_closures { + () => { + { + fn function_with_closures() { + // Create 16 closures using exponential expansion: 2^4 = 16 + go_bacterial!(create_closure 1 1 1 1); + } + let _ = function_with_closures(); + } + } +} + +fn main() { + // Create 2^8 = 256 functions, each containing 16 closures, + // resulting in 2^12 = 4096 closures total. + go_bacterial!(create_function_with_closures 1 1 1 1 1 1 1 1); +} diff --git a/tests/ui/coercion/basic-ptr-coercions.rs b/tests/ui/coercion/basic-ptr-coercions.rs new file mode 100644 index 0000000000000..4229d1fb2745f --- /dev/null +++ b/tests/ui/coercion/basic-ptr-coercions.rs @@ -0,0 +1,24 @@ +//! Tests basic pointer coercions + +//@ run-pass + +pub fn main() { + // &mut -> & + let x: &mut isize = &mut 42; + let _x: &isize = x; + let _x: &isize = &mut 42; + + // & -> *const + let x: &isize = &42; + let _x: *const isize = x; + let _x: *const isize = &42; + + // &mut -> *const + let x: &mut isize = &mut 42; + let _x: *const isize = x; + let _x: *const isize = &mut 42; + + // *mut -> *const + let _x: *mut isize = &mut 42; + let _x: *const isize = x; +} diff --git a/tests/ui/ptr-coercion.rs b/tests/ui/coercion/ptr-mutability-errors.rs similarity index 85% rename from tests/ui/ptr-coercion.rs rename to tests/ui/coercion/ptr-mutability-errors.rs index 2549bd6f134d7..391eaf0b91343 100644 --- a/tests/ui/ptr-coercion.rs +++ b/tests/ui/coercion/ptr-mutability-errors.rs @@ -1,5 +1,4 @@ -// Test coercions between pointers which don't do anything fancy like unsizing. -// These are testing that we don't lose mutability when converting to raw pointers. +//! Tests that pointer coercions preserving mutability are enforced: //@ dont-require-annotations: NOTE diff --git a/tests/ui/ptr-coercion.stderr b/tests/ui/coercion/ptr-mutability-errors.stderr similarity index 88% rename from tests/ui/ptr-coercion.stderr rename to tests/ui/coercion/ptr-mutability-errors.stderr index 8de41d2c38276..b4ded821c79cd 100644 --- a/tests/ui/ptr-coercion.stderr +++ b/tests/ui/coercion/ptr-mutability-errors.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/ptr-coercion.rs:9:25 + --> $DIR/ptr-mutability-errors.rs:8:25 | LL | let x: *mut isize = x; | ---------- ^ types differ in mutability @@ -10,7 +10,7 @@ LL | let x: *mut isize = x; found raw pointer `*const isize` error[E0308]: mismatched types - --> $DIR/ptr-coercion.rs:15:25 + --> $DIR/ptr-mutability-errors.rs:14:25 | LL | let x: *mut isize = &42; | ---------- ^^^ types differ in mutability @@ -21,7 +21,7 @@ LL | let x: *mut isize = &42; found reference `&isize` error[E0308]: mismatched types - --> $DIR/ptr-coercion.rs:21:25 + --> $DIR/ptr-mutability-errors.rs:20:25 | LL | let x: *mut isize = x; | ---------- ^ types differ in mutability diff --git a/tests/ui/const-ptr/pointer-address-stability.rs b/tests/ui/const-ptr/pointer-address-stability.rs new file mode 100644 index 0000000000000..84a36e1ddf511 --- /dev/null +++ b/tests/ui/const-ptr/pointer-address-stability.rs @@ -0,0 +1,11 @@ +//! Check that taking the address of a stack variable with `&` +//! yields a stable and comparable pointer. +//! +//! Regression test for . + +//@ run-pass + +pub fn main() { + let foo: isize = 1; + assert_eq!(&foo as *const isize, &foo as *const isize); +} diff --git a/tests/ui/auxiliary/issue-16822.rs b/tests/ui/cross-crate/auxiliary/cross-crate-refcell-match.rs similarity index 100% rename from tests/ui/auxiliary/issue-16822.rs rename to tests/ui/cross-crate/auxiliary/cross-crate-refcell-match.rs diff --git a/tests/ui/auxiliary/kinds_in_metadata.rs b/tests/ui/cross-crate/auxiliary/kinds_in_metadata.rs similarity index 100% rename from tests/ui/auxiliary/kinds_in_metadata.rs rename to tests/ui/cross-crate/auxiliary/kinds_in_metadata.rs diff --git a/tests/ui/cross-crate/cross-crate-refcell-match.rs b/tests/ui/cross-crate/cross-crate-refcell-match.rs new file mode 100644 index 0000000000000..7e46425612f33 --- /dev/null +++ b/tests/ui/cross-crate/cross-crate-refcell-match.rs @@ -0,0 +1,36 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16822 +// +//! ICE when using RefCell::borrow_mut() +//! inside match statement with cross-crate generics. +//! +//! The bug occurred when: +//! - A library defines a generic struct with RefCell and uses borrow_mut() in match +//! - Main crate implements the library trait for its own type +//! - Cross-crate generic constraint causes type inference issues +//! +//! The problematic match statement is in the auxiliary file, this file triggers it. + +//@ run-pass +//@ aux-build:cross-crate-refcell-match.rs + +extern crate cross_crate_refcell_match as lib; + +use std::cell::RefCell; + +struct App { + i: isize, +} + +impl lib::Update for App { + fn update(&mut self) { + self.i += 1; + } +} + +fn main() { + let app = App { i: 5 }; + let window = lib::Window { data: RefCell::new(app) }; + // This specific pattern (RefCell::borrow_mut in match with cross-crate generics) + // caused the ICE in the original issue + window.update(1); +} diff --git a/tests/ui/kinds-in-metadata.rs b/tests/ui/cross-crate/metadata-trait-serialization.rs similarity index 74% rename from tests/ui/kinds-in-metadata.rs rename to tests/ui/cross-crate/metadata-trait-serialization.rs index 58dffba861d57..a6645018da4ae 100644 --- a/tests/ui/kinds-in-metadata.rs +++ b/tests/ui/cross-crate/metadata-trait-serialization.rs @@ -1,12 +1,11 @@ +//! Test that trait information (like Copy) is correctly serialized in crate metadata + //@ run-pass //@ aux-build:kinds_in_metadata.rs - /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Tests that metadata serialization works for the `Copy` kind. - extern crate kinds_in_metadata; use kinds_in_metadata::f; diff --git a/tests/ui/short-error-format.rs b/tests/ui/diagnostic-flags/error-format-short.rs similarity index 56% rename from tests/ui/short-error-format.rs rename to tests/ui/diagnostic-flags/error-format-short.rs index 719870a04fb9b..4c793cd1b189b 100644 --- a/tests/ui/short-error-format.rs +++ b/tests/ui/diagnostic-flags/error-format-short.rs @@ -1,3 +1,6 @@ +//! Check that compile errors are formatted in the "short" style +//! when `--error-format=short` is used. + //@ compile-flags: --error-format=short fn foo(_: u32) {} diff --git a/tests/ui/diagnostic-flags/error-format-short.stderr b/tests/ui/diagnostic-flags/error-format-short.stderr new file mode 100644 index 0000000000000..0a097e2f623c9 --- /dev/null +++ b/tests/ui/diagnostic-flags/error-format-short.stderr @@ -0,0 +1,3 @@ +$DIR/error-format-short.rs:9:9: error[E0308]: mismatched types: expected `u32`, found `String` +$DIR/error-format-short.rs:11:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32` +error: aborting due to 2 previous errors diff --git a/tests/ui/resource-assign-is-not-copy.rs b/tests/ui/drop/drop-once-on-move.rs similarity index 71% rename from tests/ui/resource-assign-is-not-copy.rs rename to tests/ui/drop/drop-once-on-move.rs index ab42601690131..da01805807697 100644 --- a/tests/ui/resource-assign-is-not-copy.rs +++ b/tests/ui/drop/drop-once-on-move.rs @@ -1,3 +1,7 @@ +//! Check that types not implementing `Copy` are moved, not copied, during assignment +//! operations, and their `Drop` implementation is called exactly once when the +//! value goes out of scope. + //@ run-pass #![allow(non_camel_case_types)] @@ -15,9 +19,7 @@ impl<'a> Drop for r<'a> { } fn r(i: &Cell) -> r<'_> { - r { - i: i - } + r { i } } pub fn main() { diff --git a/tests/ui/resource-destruct.rs b/tests/ui/drop/drop-scope-exit.rs similarity index 53% rename from tests/ui/resource-destruct.rs rename to tests/ui/drop/drop-scope-exit.rs index 480cbe091a7a2..4d003fec7125e 100644 --- a/tests/ui/resource-destruct.rs +++ b/tests/ui/drop/drop-scope-exit.rs @@ -1,31 +1,37 @@ +//! Check that the `Drop` implementation is called when a value goes out of scope. + //@ run-pass #![allow(non_camel_case_types)] use std::cell::Cell; struct shrinky_pointer<'a> { - i: &'a Cell, + i: &'a Cell, } impl<'a> Drop for shrinky_pointer<'a> { fn drop(&mut self) { - println!("Hello!"); self.i.set(self.i.get() - 1); + println!("Hello!"); + self.i.set(self.i.get() - 1); } } impl<'a> shrinky_pointer<'a> { - pub fn look_at(&self) -> isize { return self.i.get(); } + pub fn look_at(&self) -> isize { + return self.i.get(); + } } fn shrinky_pointer(i: &Cell) -> shrinky_pointer<'_> { - shrinky_pointer { - i: i - } + shrinky_pointer { i } } pub fn main() { let my_total = &Cell::new(10); - { let pt = shrinky_pointer(my_total); assert_eq!(pt.look_at(), 10); } + { + let pt = shrinky_pointer(my_total); + assert_eq!(pt.look_at(), 10); + } println!("my_total = {}", my_total.get()); assert_eq!(my_total.get(), 9); } diff --git a/tests/ui/auxiliary/delegate_macro.rs b/tests/ui/fn/auxiliary/delegate_macro.rs similarity index 100% rename from tests/ui/auxiliary/delegate_macro.rs rename to tests/ui/fn/auxiliary/delegate_macro.rs diff --git a/tests/ui/not-enough-arguments.rs b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs similarity index 82% rename from tests/ui/not-enough-arguments.rs rename to tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs index ec660a1de81be..b2f80ba1bf62f 100644 --- a/tests/ui/not-enough-arguments.rs +++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs @@ -1,15 +1,15 @@ +//! Checks clean diagnostics for argument count mismatches without unrelated errors. +//! +//! `delegate!` part related: + //@ aux-build: delegate_macro.rs extern crate delegate_macro; use delegate_macro::delegate; -// Check that the only error msg we report is the -// mismatch between the # of params, and not other -// unrelated errors. fn foo(a: isize, b: isize, c: isize, d: isize) { panic!(); } -// Check that all arguments are shown in the error message, even if they're across multiple lines. fn bar(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) { println!("{}", a); println!("{}", b); @@ -37,6 +37,7 @@ struct Bar; impl Bar { fn foo(a: u8, b: u8) {} + fn bar() { delegate_local!(foo); delegate!(foo); diff --git a/tests/ui/not-enough-arguments.stderr b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr similarity index 83% rename from tests/ui/not-enough-arguments.stderr rename to tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr index 908d0273bbecd..6af7671af03bf 100644 --- a/tests/ui/not-enough-arguments.stderr +++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr @@ -1,5 +1,5 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/not-enough-arguments.rs:24:9 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:24:9 | LL | ::$method(8) | ^^^^^^^^^^^^^^^--- argument #2 of type `u8` is missing @@ -8,7 +8,7 @@ LL | delegate_local!(foo); | -------------------- in this macro invocation | note: associated function defined here - --> $DIR/not-enough-arguments.rs:39:8 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:39:8 | LL | fn foo(a: u8, b: u8) {} | ^^^ ----- @@ -19,20 +19,20 @@ LL | ::$method(8, /* u8 */) | ++++++++++ error[E0061]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/not-enough-arguments.rs:42:9 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:43:9 | LL | delegate!(foo); | ^^^^^^^^^^^^^^ argument #2 of type `u8` is missing | note: associated function defined here - --> $DIR/not-enough-arguments.rs:39:8 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:39:8 | LL | fn foo(a: u8, b: u8) {} | ^^^ ----- = note: this error originates in the macro `delegate` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0061]: this function takes 2 arguments but 1 argument was supplied - --> $DIR/not-enough-arguments.rs:31:9 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:31:9 | LL | <$from>::$method(8) | ^^^^^^^^^^^^^^^^--- argument #2 of type `u8` is missing @@ -41,7 +41,7 @@ LL | delegate_from!(Bar, foo); | ------------------------ in this macro invocation | note: associated function defined here - --> $DIR/not-enough-arguments.rs:39:8 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:39:8 | LL | fn foo(a: u8, b: u8) {} | ^^^ ----- @@ -52,13 +52,13 @@ LL | <$from>::$method(8, /* u8 */) | ++++++++++ error[E0061]: this function takes 4 arguments but 3 arguments were supplied - --> $DIR/not-enough-arguments.rs:49:5 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:50:5 | LL | foo(1, 2, 3); | ^^^--------- argument #4 of type `isize` is missing | note: function defined here - --> $DIR/not-enough-arguments.rs:8:4 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:9:4 | LL | fn foo(a: isize, b: isize, c: isize, d: isize) { | ^^^ -------- @@ -68,13 +68,13 @@ LL | foo(1, 2, 3, /* isize */); | +++++++++++++ error[E0061]: this function takes 6 arguments but 3 arguments were supplied - --> $DIR/not-enough-arguments.rs:51:5 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:52:5 | LL | bar(1, 2, 3); | ^^^--------- three arguments of type `i32`, `i32`, and `i32` are missing | note: function defined here - --> $DIR/not-enough-arguments.rs:13:4 + --> $DIR/fn-arg-count-mismatch-diagnostics.rs:13:4 | LL | fn bar(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) { | ^^^ ------ ------ ------ diff --git a/tests/ui/fn/mutable-function-parameters.rs b/tests/ui/fn/mutable-function-parameters.rs new file mode 100644 index 0000000000000..5045a783f0492 --- /dev/null +++ b/tests/ui/fn/mutable-function-parameters.rs @@ -0,0 +1,24 @@ +//! Test that function and closure parameters marked as `mut` can be mutated +//! within the function body. + +//@ run-pass + +fn f(mut y: Box) { + *y = 5; + assert_eq!(*y, 5); +} + +fn g() { + let frob = |mut q: Box| { + *q = 2; + assert_eq!(*q, 2); + }; + let w = Box::new(37); + frob(w); +} + +pub fn main() { + let z = Box::new(17); + f(z); + g(); +} diff --git a/tests/ui/generics/generic-params-nested-fn-scope-error.rs b/tests/ui/generics/generic-params-nested-fn-scope-error.rs new file mode 100644 index 0000000000000..eaf514da33763 --- /dev/null +++ b/tests/ui/generics/generic-params-nested-fn-scope-error.rs @@ -0,0 +1,14 @@ +//! Test that generic parameters from an outer function are not accessible +//! in nested functions. + +fn foo(v: Vec) -> U { + fn bar(w: [U]) -> U { + //~^ ERROR can't use generic parameters from outer item + //~| ERROR can't use generic parameters from outer item + return w[0]; + } + + return bar(v); +} + +fn main() {} diff --git a/tests/ui/nested-ty-params.stderr b/tests/ui/generics/generic-params-nested-fn-scope-error.stderr similarity index 62% rename from tests/ui/nested-ty-params.stderr rename to tests/ui/generics/generic-params-nested-fn-scope-error.stderr index 7ca65b421b25f..7fd1069c651fa 100644 --- a/tests/ui/nested-ty-params.stderr +++ b/tests/ui/generics/generic-params-nested-fn-scope-error.stderr @@ -1,19 +1,19 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:2:16 + --> $DIR/generic-params-nested-fn-scope-error.rs:5:16 | -LL | fn hd(v: Vec ) -> U { - | - type parameter from outer item -LL | fn hd1(w: [U]) -> U { return w[0]; } +LL | fn foo(v: Vec) -> U { + | - type parameter from outer item +LL | fn bar(w: [U]) -> U { | - ^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` error[E0401]: can't use generic parameters from outer item - --> $DIR/nested-ty-params.rs:2:23 + --> $DIR/generic-params-nested-fn-scope-error.rs:5:23 | -LL | fn hd(v: Vec ) -> U { - | - type parameter from outer item -LL | fn hd1(w: [U]) -> U { return w[0]; } +LL | fn foo(v: Vec) -> U { + | - type parameter from outer item +LL | fn bar(w: [U]) -> U { | - ^ use of generic parameter from outer item | | | help: try introducing a local generic parameter here: `` diff --git a/tests/ui/seq-args.rs b/tests/ui/generics/trait-incorrect-generic-args.rs similarity index 72% rename from tests/ui/seq-args.rs rename to tests/ui/generics/trait-incorrect-generic-args.rs index 627dfcc31986a..9715100b19cc7 100644 --- a/tests/ui/seq-args.rs +++ b/tests/ui/generics/trait-incorrect-generic-args.rs @@ -1,5 +1,7 @@ +//! Check for compilation errors when a trait is used with an incorrect number of generic arguments. + fn main() { - trait Seq { } + trait Seq {} impl Seq for Vec { //~^ ERROR trait takes 0 generic arguments but 1 generic argument diff --git a/tests/ui/seq-args.stderr b/tests/ui/generics/trait-incorrect-generic-args.stderr similarity index 76% rename from tests/ui/seq-args.stderr rename to tests/ui/generics/trait-incorrect-generic-args.stderr index 6e0d484d013d3..afc4ff03d949d 100644 --- a/tests/ui/seq-args.stderr +++ b/tests/ui/generics/trait-incorrect-generic-args.stderr @@ -1,5 +1,5 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/seq-args.rs:4:13 + --> $DIR/trait-incorrect-generic-args.rs:6:13 | LL | impl Seq for Vec { | ^^^--- help: remove the unnecessary generics @@ -7,13 +7,13 @@ LL | impl Seq for Vec { | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/seq-args.rs:2:11 + --> $DIR/trait-incorrect-generic-args.rs:4:11 | -LL | trait Seq { } +LL | trait Seq {} | ^^^ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/seq-args.rs:9:10 + --> $DIR/trait-incorrect-generic-args.rs:11:10 | LL | impl Seq for u32 { | ^^^------ help: remove the unnecessary generics @@ -21,9 +21,9 @@ LL | impl Seq for u32 { | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/seq-args.rs:2:11 + --> $DIR/trait-incorrect-generic-args.rs:4:11 | -LL | trait Seq { } +LL | trait Seq {} | ^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/issue-15924.rs b/tests/ui/higher-ranked/higher-ranked-encoding.rs similarity index 68% rename from tests/ui/issue-15924.rs rename to tests/ui/higher-ranked/higher-ranked-encoding.rs index eb2aef9cee12b..463e0f50e5379 100644 --- a/tests/ui/issue-15924.rs +++ b/tests/ui/higher-ranked/higher-ranked-encoding.rs @@ -1,9 +1,7 @@ -//@ run-pass +//! Regression test for https://github.com/rust-lang/rust/issues/15924 -#![allow(unused_imports)] -#![allow(unused_must_use)] +//@ run-pass -use std::fmt; use std::marker::PhantomData; trait Encoder { @@ -26,9 +24,8 @@ impl Encoder for JsonEncoder<'_> { type Error = (); } -fn encode_json Encodable>>( - object: &T, -) -> Result { +// This function uses higher-ranked trait bounds, which previously caused ICE +fn encode_json Encodable>>(object: &T) -> Result { let s = String::new(); { let mut encoder = JsonEncoder(PhantomData); @@ -37,13 +34,15 @@ fn encode_json Encodable>>( Ok(s) } +// Structure with HRTB constraint that was problematic struct Foo Encodable>> { v: T, } +// Drop implementation that exercises the HRTB bounds impl Encodable>> Drop for Foo { fn drop(&mut self) { - encode_json(&self.v); + let _ = encode_json(&self.v); } } diff --git a/tests/ui/stdio-is-blocking.rs b/tests/ui/io-checks/io-stdout-blocking-writes.rs similarity index 78% rename from tests/ui/stdio-is-blocking.rs rename to tests/ui/io-checks/io-stdout-blocking-writes.rs index 615530dcd47e4..1197b7f43be8d 100644 --- a/tests/ui/stdio-is-blocking.rs +++ b/tests/ui/io-checks/io-stdout-blocking-writes.rs @@ -1,10 +1,12 @@ +//! Check that writes to standard output are blocking, avoiding interleaving +//! even with concurrent writes from multiple threads. + //@ run-pass //@ needs-subprocess -use std::env; use std::io::prelude::*; use std::process::Command; -use std::thread; +use std::{env, thread}; const THREADS: usize = 20; const WRITES: usize = 100; @@ -33,14 +35,16 @@ fn parent() { } fn child() { - let threads = (0..THREADS).map(|_| { - thread::spawn(|| { - let buf = [b'a'; WRITE_SIZE]; - for _ in 0..WRITES { - write_all(&buf); - } + let threads = (0..THREADS) + .map(|_| { + thread::spawn(|| { + let buf = [b'a'; WRITE_SIZE]; + for _ in 0..WRITES { + write_all(&buf); + } + }) }) - }).collect::>(); + .collect::>(); for thread in threads { thread.join().unwrap(); @@ -63,8 +67,8 @@ fn write_all(buf: &[u8]) { fn write_all(buf: &[u8]) { use std::fs::File; use std::mem; - use std::os::windows::raw::*; use std::os::windows::prelude::*; + use std::os::windows::raw::*; const STD_OUTPUT_HANDLE: u32 = (-11i32) as u32; diff --git a/tests/ui/print-stdout-eprint-stderr.rs b/tests/ui/io-checks/stdout-stderr-separation.rs similarity index 88% rename from tests/ui/print-stdout-eprint-stderr.rs rename to tests/ui/io-checks/stdout-stderr-separation.rs index 4b356e2fe6172..1bb3f16d3a1fb 100644 --- a/tests/ui/print-stdout-eprint-stderr.rs +++ b/tests/ui/io-checks/stdout-stderr-separation.rs @@ -1,3 +1,6 @@ +//! Test that print!/println! output to stdout and eprint!/eprintln! +//! output to stderr correctly. + //@ run-pass //@ needs-subprocess diff --git a/tests/ui/issue-16822.rs b/tests/ui/issue-16822.rs deleted file mode 100644 index 94d89f88f4705..0000000000000 --- a/tests/ui/issue-16822.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ run-pass -//@ aux-build:issue-16822.rs - -extern crate issue_16822 as lib; - -use std::cell::RefCell; - -struct App { - i: isize -} - -impl lib::Update for App { - fn update(&mut self) { - self.i += 1; - } -} - -fn main(){ - let app = App { i: 5 }; - let window = lib::Window { data: RefCell::new(app) }; - window.update(1); -} diff --git a/tests/ui/item-name-overload.rs b/tests/ui/item-name-overload.rs deleted file mode 100644 index dd2925aa53fe4..0000000000000 --- a/tests/ui/item-name-overload.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] - - - - -mod foo { - pub fn baz() { } -} - -mod bar { - pub fn baz() { } -} - -pub fn main() { } diff --git a/tests/ui/kinds-of-primitive-impl.rs b/tests/ui/kinds-of-primitive-impl.rs deleted file mode 100644 index f1c2ee8e5506e..0000000000000 --- a/tests/ui/kinds-of-primitive-impl.rs +++ /dev/null @@ -1,26 +0,0 @@ -impl u8 { -//~^ error: cannot define inherent `impl` for primitive types - pub const B: u8 = 0; -} - -impl str { -//~^ error: cannot define inherent `impl` for primitive types - fn foo() {} - fn bar(self) {} //~ ERROR: size for values of type `str` cannot be known -} - -impl char { -//~^ error: cannot define inherent `impl` for primitive types - pub const B: u8 = 0; - pub const C: u8 = 0; - fn foo() {} - fn bar(self) {} -} - -struct MyType; -impl &MyType { -//~^ error: cannot define inherent `impl` for primitive types - pub fn for_ref(self) {} -} - -fn main() {} diff --git a/tests/ui/last-use-in-block.rs b/tests/ui/last-use-in-block.rs deleted file mode 100644 index 4a166b97bda4b..0000000000000 --- a/tests/ui/last-use-in-block.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -#![allow(unused_parens)] -// Issue #1818 - - -fn lp(s: String, mut f: F) -> T where F: FnMut(String) -> T { - while false { - let r = f(s); - return (r); - } - panic!(); -} - -fn apply(s: String, mut f: F) -> T where F: FnMut(String) -> T { - fn g(s: String, mut f: F) -> T where F: FnMut(String) -> T {f(s)} - g(s, |v| { let r = f(v); r }) -} - -pub fn main() {} diff --git a/tests/ui/last-use-in-cap-clause.rs b/tests/ui/last-use-in-cap-clause.rs deleted file mode 100644 index 23c263c98058f..0000000000000 --- a/tests/ui/last-use-in-cap-clause.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -// Make sure #1399 stays fixed - -struct A { a: Box } - -fn foo() -> Box isize + 'static> { - let k: Box<_> = Box::new(22); - let _u = A {a: k.clone()}; - let result = || 22; - Box::new(result) -} - -pub fn main() { - assert_eq!(foo()(), 22); -} diff --git a/tests/ui/last-use-is-capture.rs b/tests/ui/last-use-is-capture.rs deleted file mode 100644 index 6e07895f1d301..0000000000000 --- a/tests/ui/last-use-is-capture.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -// Make sure #1399 stays fixed - -struct A { a: Box } - -pub fn main() { - fn invoke(f: F) where F: FnOnce() { f(); } - let k: Box<_> = 22.into(); - let _u = A {a: k.clone()}; - invoke(|| println!("{}", k.clone()) ) -} diff --git a/tests/ui/nullable-pointer-size.rs b/tests/ui/layout/null-pointer-optimization-sizes.rs similarity index 65% rename from tests/ui/nullable-pointer-size.rs rename to tests/ui/layout/null-pointer-optimization-sizes.rs index aabdfa140dff6..95310b32e25f3 100644 --- a/tests/ui/nullable-pointer-size.rs +++ b/tests/ui/layout/null-pointer-optimization-sizes.rs @@ -1,10 +1,20 @@ +//! null pointer optimization preserves type sizes. +//! +//! Verifies that Option has the same size as T for non-null pointer types, +//! and for custom enums that have a niche. + //@ run-pass +// Needs for Nothing variat in Enum #![allow(dead_code)] use std::mem; -enum E { Thing(isize, T), Nothing((), ((), ()), [i8; 0]) } +enum E { + Thing(isize, T), + Nothing((), ((), ()), [i8; 0]), +} + struct S(isize, T); // These are macros so we get useful assert messages. @@ -12,20 +22,20 @@ struct S(isize, T); macro_rules! check_option { ($T:ty) => { assert_eq!(mem::size_of::>(), mem::size_of::<$T>()); - } + }; } macro_rules! check_fancy { ($T:ty) => { assert_eq!(mem::size_of::>(), mem::size_of::>()); - } + }; } macro_rules! check_type { ($T:ty) => {{ check_option!($T); check_fancy!($T); - }} + }}; } pub fn main() { diff --git a/tests/ui/nullable-pointer-iotareduction.rs b/tests/ui/layout/null-pointer-optimization.rs similarity index 62% rename from tests/ui/nullable-pointer-iotareduction.rs rename to tests/ui/layout/null-pointer-optimization.rs index 1b73164c9fc74..5e77c8d22ab22 100644 --- a/tests/ui/nullable-pointer-iotareduction.rs +++ b/tests/ui/layout/null-pointer-optimization.rs @@ -1,27 +1,34 @@ -//@ run-pass +//! null pointer optimization with iota-reduction for enums. +//! +//! Iota-reduction is a rule from the Calculus of (Co-)Inductive Constructions: +//! "a destructor applied to an object built from a constructor behaves as expected". +//! See . +//! +//! This test verifies that null pointer optimization works correctly for both +//! Option and custom enums, accounting for pointers and regions. -// Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions, -// which "says that a destructor applied to an object built from a constructor -// behaves as expected". -- https://coq.inria.fr/doc/language/core/conversion.html#iota-reduction -// -// It's a little more complicated here, because of pointers and regions and -// trying to get assert failure messages that at least identify which case -// failed. +//@ run-pass #![allow(unpredictable_function_pointer_comparisons)] -enum E { Thing(isize, T), #[allow(dead_code)] Nothing((), ((), ()), [i8; 0]) } +enum E { + Thing(isize, T), + #[allow(dead_code)] + Nothing((), ((), ()), [i8; 0]), +} + impl E { fn is_none(&self) -> bool { match *self { E::Thing(..) => false, - E::Nothing(..) => true + E::Nothing(..) => true, } } + fn get_ref(&self) -> (isize, &T) { match *self { - E::Nothing(..) => panic!("E::get_ref(Nothing::<{}>)", stringify!(T)), - E::Thing(x, ref y) => (x, y) + E::Nothing(..) => panic!("E::get_ref(Nothing::<{}>)", stringify!(T)), + E::Thing(x, ref y) => (x, y), } } } @@ -36,7 +43,7 @@ macro_rules! check_option { let s_ = Some::<$T>(e); let $v = s_.as_ref().unwrap(); $chk - }} + }}; } macro_rules! check_fancy { @@ -48,11 +55,10 @@ macro_rules! check_fancy { let e = $e; let t_ = E::Thing::<$T>(23, e); match t_.get_ref() { - (23, $v) => { $chk } - _ => panic!("Thing::<{}>(23, {}).get_ref() != (23, _)", - stringify!($T), stringify!($e)) + (23, $v) => $chk, + _ => panic!("Thing::<{}>(23, {}).get_ref() != (23, _)", stringify!($T), stringify!($e)), } - }} + }}; } macro_rules! check_type { @@ -67,7 +73,5 @@ pub fn main() { check_type!(Box::new(18), Box); check_type!("foo".to_string(), String); check_type!(vec![20, 22], Vec); - check_type!(main, fn(), |pthing| { - assert_eq!(main as fn(), *pthing as fn()) - }); + check_type!(main, fn(), |pthing| assert_eq!(main as fn(), *pthing as fn())); } diff --git a/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs new file mode 100644 index 0000000000000..1cd41114bbdd5 --- /dev/null +++ b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.rs @@ -0,0 +1,25 @@ +//! Test closure parameter type inference and type mismatch errors. +//! +//! Related to . + +//@ dont-require-annotations: NOTE + +fn let_in(x: T, f: F) +where + F: FnOnce(T), +{ +} + +fn main() { + let_in(3u32, |i| { + assert!(i == 3i32); + //~^ ERROR mismatched types + //~| NOTE expected `u32`, found `i32` + }); + + let_in(3i32, |i| { + assert!(i == 3u32); + //~^ ERROR mismatched types + //~| NOTE expected `i32`, found `u32` + }); +} diff --git a/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr new file mode 100644 index 0000000000000..c75e90ce4ef11 --- /dev/null +++ b/tests/ui/mismatched_types/closure-parameter-type-inference-mismatch.stderr @@ -0,0 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/closure-parameter-type-inference-mismatch.rs:15:22 + | +LL | assert!(i == 3i32); + | - ^^^^ expected `u32`, found `i32` + | | + | expected because this is `u32` + | +help: change the type of the numeric literal from `i32` to `u32` + | +LL - assert!(i == 3i32); +LL + assert!(i == 3u32); + | + +error[E0308]: mismatched types + --> $DIR/closure-parameter-type-inference-mismatch.rs:21:22 + | +LL | assert!(i == 3u32); + | - ^^^^ expected `i32`, found `u32` + | | + | expected because this is `i32` + | +help: change the type of the numeric literal from `u32` to `i32` + | +LL - assert!(i == 3u32); +LL + assert!(i == 3i32); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/point-to-type-err-cause-on-impl-trait-return-2.rs b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs similarity index 50% rename from tests/ui/point-to-type-err-cause-on-impl-trait-return-2.rs rename to tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs index 50f1fe873cb5f..6711d303eb3db 100644 --- a/tests/ui/point-to-type-err-cause-on-impl-trait-return-2.rs +++ b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.rs @@ -1,4 +1,8 @@ -fn unrelated() -> Result<(), std::string::ParseError> { // #57664 +//! Regression test for . +//! Checks that compiler doesn't get confused by `?` operator and complex +//! return types when reporting type mismatches. + +fn unrelated() -> Result<(), std::string::ParseError> { let x = 0; match x { diff --git a/tests/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr similarity index 84% rename from tests/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr rename to tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr index 34aaea5b70bbe..38392fe99d663 100644 --- a/tests/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr +++ b/tests/ui/mismatched_types/type-error-diagnostic-in-complex-return.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return-2.rs:9:41 + --> $DIR/type-error-diagnostic-in-complex-return.rs:13:41 | LL | let value: &bool = unsafe { &42 }; | ^^^ expected `&bool`, found `&{integer}` diff --git a/tests/ui/modules/mod-same-item-names.rs b/tests/ui/modules/mod-same-item-names.rs new file mode 100644 index 0000000000000..1e9a9caa5fc5d --- /dev/null +++ b/tests/ui/modules/mod-same-item-names.rs @@ -0,0 +1,15 @@ +//! Test that items with identical names can coexist in different modules + +//@ run-pass + +#![allow(dead_code)] + +mod foo { + pub fn baz() {} +} + +mod bar { + pub fn baz() {} +} + +pub fn main() {} diff --git a/tests/ui/mut-function-arguments.rs b/tests/ui/mut-function-arguments.rs deleted file mode 100644 index 01c264fce0389..0000000000000 --- a/tests/ui/mut-function-arguments.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass - -fn f(mut y: Box) { - *y = 5; - assert_eq!(*y, 5); -} - -fn g() { - let frob = |mut q: Box| { *q = 2; assert_eq!(*q, 2); }; - let w = Box::new(37); - frob(w); - -} - -pub fn main() { - let z = Box::new(17); - f(z); - g(); -} diff --git a/tests/ui/mutual-recursion-group.rs b/tests/ui/mutual-recursion-group.rs deleted file mode 100644 index f83150af7dc85..0000000000000 --- a/tests/ui/mutual-recursion-group.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass - -#![allow(non_camel_case_types)] -#![allow(dead_code)] - - -enum colour { red, green, blue, } - -enum tree { children(Box), leaf(colour), } - -enum list { cons(Box, Box), nil, } - -enum small_list { kons(isize, Box), neel, } - -pub fn main() { } diff --git a/tests/ui/myriad-closures.rs b/tests/ui/myriad-closures.rs deleted file mode 100644 index 541d27d5de407..0000000000000 --- a/tests/ui/myriad-closures.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ run-pass -// This test case tests whether we can handle code bases that contain a high -// number of closures, something that needs special handling in the MingGW -// toolchain. -// See https://github.com/rust-lang/rust/issues/34793 for more information. - -// Make sure we don't optimize anything away: -//@ compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals - -// Expand something exponentially -macro_rules! go_bacterial { - ($mac:ident) => ($mac!()); - ($mac:ident 1 $($t:tt)*) => ( - go_bacterial!($mac $($t)*); - go_bacterial!($mac $($t)*); - ) -} - -macro_rules! mk_closure { - () => ((move || {})()) -} - -macro_rules! mk_fn { - () => { - { - fn function() { - // Make 16 closures - go_bacterial!(mk_closure 1 1 1 1); - } - let _ = function(); - } - } -} - -fn main() { - // Make 2^8 functions, each containing 16 closures, - // resulting in 2^12 closures overall. - go_bacterial!(mk_fn 1 1 1 1 1 1 1 1); -} diff --git a/tests/ui/nested-block-comment.rs b/tests/ui/nested-block-comment.rs deleted file mode 100644 index 008df27e0e2a2..0000000000000 --- a/tests/ui/nested-block-comment.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass - -/* This test checks that nested comments are supported - - /* - This should not panic - */ -*/ - -pub fn main() { -} diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/nested-cfg-attrs.rs deleted file mode 100644 index 941807a84310e..0000000000000 --- a/tests/ui/nested-cfg-attrs.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg_attr(all(), cfg_attr(all(), cfg(false)))] -fn f() {} - -fn main() { f() } //~ ERROR cannot find function `f` in this scope diff --git a/tests/ui/nested-class.rs b/tests/ui/nested-class.rs deleted file mode 100644 index f84ab40dd1d41..0000000000000 --- a/tests/ui/nested-class.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass - -#![allow(non_camel_case_types)] - -pub fn main() { - struct b { - i: isize, - } - - impl b { - fn do_stuff(&self) -> isize { return 37; } - } - - fn b(i:isize) -> b { - b { - i: i - } - } - - // fn b(x:isize) -> isize { panic!(); } - - let z = b(42); - assert_eq!(z.i, 42); - assert_eq!(z.do_stuff(), 37); -} diff --git a/tests/ui/nested-ty-params.rs b/tests/ui/nested-ty-params.rs deleted file mode 100644 index c00c3bc337230..0000000000000 --- a/tests/ui/nested-ty-params.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn hd(v: Vec ) -> U { - fn hd1(w: [U]) -> U { return w[0]; } - //~^ ERROR can't use generic parameters from outer item - //~| ERROR can't use generic parameters from outer item - - return hd1(v); -} - -fn main() {} diff --git a/tests/ui/occurs-check-2.rs b/tests/ui/occurs-check-2.rs deleted file mode 100644 index 9289a8e870a18..0000000000000 --- a/tests/ui/occurs-check-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - - let f; - let g; - - g = f; - //~^ ERROR overflow assigning `Box<_>` to `_` - f = Box::new(g); -} diff --git a/tests/ui/occurs-check-3.rs b/tests/ui/occurs-check-3.rs deleted file mode 100644 index 377a043daf3f6..0000000000000 --- a/tests/ui/occurs-check-3.rs +++ /dev/null @@ -1,11 +0,0 @@ -// From Issue #778 - -enum Clam { A(T) } -fn main() { - let c; - c = Clam::A(c); - //~^ ERROR overflow assigning `Clam<_>` to `_` - match c { - Clam::A::(_) => { } - } -} diff --git a/tests/ui/occurs-check.rs b/tests/ui/occurs-check.rs deleted file mode 100644 index 638b9b6d7e4c2..0000000000000 --- a/tests/ui/occurs-check.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let f; - f = Box::new(f); - //~^ ERROR overflow assigning `Box<_>` to `_` -} diff --git a/tests/ui/opeq.rs b/tests/ui/opeq.rs deleted file mode 100644 index 956ea0684fa70..0000000000000 --- a/tests/ui/opeq.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass - -pub fn main() { - let mut x: isize = 1; - x *= 2; - println!("{}", x); - assert_eq!(x, 2); - x += 3; - println!("{}", x); - assert_eq!(x, 5); - x *= x; - println!("{}", x); - assert_eq!(x, 25); - x /= 5; - println!("{}", x); - assert_eq!(x, 5); -} diff --git a/tests/ui/oom_unwind.rs b/tests/ui/panics/oom-panic-unwind.rs similarity index 86% rename from tests/ui/oom_unwind.rs rename to tests/ui/panics/oom-panic-unwind.rs index be5e63d430b70..5974ad91406f3 100644 --- a/tests/ui/oom_unwind.rs +++ b/tests/ui/panics/oom-panic-unwind.rs @@ -1,3 +1,5 @@ +//! Test that out-of-memory conditions trigger catchable panics with `-Z oom=panic`. + //@ compile-flags: -Z oom=panic //@ run-pass //@ no-prefer-dynamic diff --git a/tests/ui/parser/doc-comment-in-generic.rs b/tests/ui/parser/doc-comment-in-generic.rs new file mode 100644 index 0000000000000..2596496763bac --- /dev/null +++ b/tests/ui/parser/doc-comment-in-generic.rs @@ -0,0 +1,13 @@ +//! Tests correct parsing of doc comments on generic parameters in traits. +//! Checks that compiler doesn't panic when processing this. + +//@ check-pass + +#![crate_type = "lib"] + +pub trait Layer< + /// Documentation for generic parameter. + Input, +> +{ +} diff --git a/tests/ui/parser/nested-block-comments.rs b/tests/ui/parser/nested-block-comments.rs new file mode 100644 index 0000000000000..8fe778963619c --- /dev/null +++ b/tests/ui/parser/nested-block-comments.rs @@ -0,0 +1,34 @@ +//! Test that nested block comments are properly supported by the parser. +//! +//! See . + +//@ run-pass + +/* This test checks that nested comments are supported + + /* This is a nested comment + /* And this is even more deeply nested */ + Back to the first level of nesting + */ + + /* Another nested comment at the same level */ +*/ + +/* Additional test cases for nested comments */ + +#[rustfmt::skip] +/* + /* Level 1 + /* Level 2 + /* Level 3 */ + */ + */ +*/ + +pub fn main() { + // Check that code after nested comments works correctly + let _x = 42; + + /* Even inline /* nested */ comments work */ + let _y = /* nested /* comment */ test */ 100; +} diff --git a/tests/ui/parser/raw/raw-string-literals.rs b/tests/ui/parser/raw/raw-string-literals.rs new file mode 100644 index 0000000000000..2272f268b3675 Binary files /dev/null and b/tests/ui/parser/raw/raw-string-literals.rs differ diff --git a/tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.rs b/tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.rs new file mode 100644 index 0000000000000..42b0b9ac44dd6 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.rs @@ -0,0 +1,24 @@ +//! Tests how we behave when the user attempts to mutate an immutable +//! binding that was introduced by either `ref` or `ref mut` +//! patterns. +//! +//! Such bindings cannot be made mutable via the mere addition of the +//! `mut` keyword, and thus we want to check that the compiler does not +//! suggest doing so. + +fn main() { + let (mut one_two, mut three_four) = ((1, 2), (3, 4)); + + // Bind via pattern: + // - `a` as immutable reference (`ref`) + // - `b` as mutable reference (`ref mut`) + let &mut (ref a, ref mut b) = &mut one_two; + + // Attempt to reassign immutable `ref`-bound variable + a = &three_four.0; + //~^ ERROR cannot assign twice to immutable variable `a` + + // Attempt to reassign mutable `ref mut`-bound variable + b = &mut three_four.1; + //~^ ERROR cannot assign twice to immutable variable `b` +} diff --git a/tests/ui/reassign-ref-mut.stderr b/tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.stderr similarity index 85% rename from tests/ui/reassign-ref-mut.stderr rename to tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.stderr index e623578e02522..e04eb1dd25cee 100644 --- a/tests/ui/reassign-ref-mut.stderr +++ b/tests/ui/pattern/move-ref-patterns/pattern-ref-bindings-reassignment.stderr @@ -1,13 +1,14 @@ error[E0384]: cannot assign twice to immutable variable `a` - --> $DIR/reassign-ref-mut.rs:12:5 + --> $DIR/pattern-ref-bindings-reassignment.rs:18:5 | LL | let &mut (ref a, ref mut b) = &mut one_two; | ----- first assignment to `a` +... LL | a = &three_four.0; | ^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/reassign-ref-mut.rs:14:5 + --> $DIR/pattern-ref-bindings-reassignment.rs:22:5 | LL | let &mut (ref a, ref mut b) = &mut one_two; | --------- first assignment to `b` diff --git a/tests/ui/pptypedef.rs b/tests/ui/pptypedef.rs deleted file mode 100644 index d5f43df9d85c5..0000000000000 --- a/tests/ui/pptypedef.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ dont-require-annotations: NOTE - -fn let_in(x: T, f: F) where F: FnOnce(T) {} - -fn main() { - let_in(3u32, |i| { assert!(i == 3i32); }); - //~^ ERROR mismatched types - //~| NOTE expected `u32`, found `i32` - - let_in(3i32, |i| { assert!(i == 3u32); }); - //~^ ERROR mismatched types - //~| NOTE expected `i32`, found `u32` -} diff --git a/tests/ui/pptypedef.stderr b/tests/ui/pptypedef.stderr deleted file mode 100644 index a6d673e61c698..0000000000000 --- a/tests/ui/pptypedef.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/pptypedef.rs:6:37 - | -LL | let_in(3u32, |i| { assert!(i == 3i32); }); - | - ^^^^ expected `u32`, found `i32` - | | - | expected because this is `u32` - | -help: change the type of the numeric literal from `i32` to `u32` - | -LL - let_in(3u32, |i| { assert!(i == 3i32); }); -LL + let_in(3u32, |i| { assert!(i == 3u32); }); - | - -error[E0308]: mismatched types - --> $DIR/pptypedef.rs:10:37 - | -LL | let_in(3i32, |i| { assert!(i == 3u32); }); - | - ^^^^ expected `i32`, found `u32` - | | - | expected because this is `i32` - | -help: change the type of the numeric literal from `u32` to `i32` - | -LL - let_in(3i32, |i| { assert!(i == 3u32); }); -LL + let_in(3i32, |i| { assert!(i == 3i32); }); - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/primitive-binop-lhs-mut.rs b/tests/ui/primitive-binop-lhs-mut.rs deleted file mode 100644 index d988e2ed14fc4..0000000000000 --- a/tests/ui/primitive-binop-lhs-mut.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - -fn main() { - let x = Box::new(0); - assert_eq!(0, *x + { drop(x); let _ = Box::new(main); 0 }); -} diff --git a/tests/ui/print-calling-conventions.rs b/tests/ui/print-calling-conventions.rs deleted file mode 100644 index 302ed088142d8..0000000000000 --- a/tests/ui/print-calling-conventions.rs +++ /dev/null @@ -1,2 +0,0 @@ -//@ compile-flags: --print calling-conventions -//@ build-pass diff --git a/tests/ui/print-request/print-calling-conventions.rs b/tests/ui/print-request/print-calling-conventions.rs new file mode 100644 index 0000000000000..cefaa0d9b6fc0 --- /dev/null +++ b/tests/ui/print-request/print-calling-conventions.rs @@ -0,0 +1,4 @@ +//! Test that `--print calling-conventions` outputs all supported calling conventions. + +//@ compile-flags: --print calling-conventions +//@ build-pass diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-request/print-calling-conventions.stdout similarity index 100% rename from tests/ui/print-calling-conventions.stdout rename to tests/ui/print-request/print-calling-conventions.stdout diff --git a/tests/ui/project-cache-issue-31849.rs b/tests/ui/project-cache-issue-31849.rs deleted file mode 100644 index 29c278171a61b..0000000000000 --- a/tests/ui/project-cache-issue-31849.rs +++ /dev/null @@ -1,65 +0,0 @@ -//@ run-pass -// Regression test for #31849: the problem here was actually a performance -// cliff, but I'm adding the test for reference. - -pub trait Upcast { - fn upcast(self) -> T; -} - -impl Upcast<(T1, T2)> for (S1,S2) - where S1: Upcast, - S2: Upcast, -{ - fn upcast(self) -> (T1, T2) { (self.0.upcast(), self.1.upcast()) } -} - -impl Upcast<()> for () -{ - fn upcast(self) -> () { () } -} - -pub trait ToStatic { - type Static: 'static; - fn to_static(self) -> Self::Static where Self: Sized; -} - -impl ToStatic for (T, U) - where T: ToStatic, - U: ToStatic -{ - type Static = (T::Static, U::Static); - fn to_static(self) -> Self::Static { (self.0.to_static(), self.1.to_static()) } -} - -impl ToStatic for () -{ - type Static = (); - fn to_static(self) -> () { () } -} - - -trait Factory { - type Output; - fn build(&self) -> Self::Output; -} - -impl Factory for (S, T) - where S: Factory, - T: Factory, - S::Output: ToStatic, - ::Static: Upcast, -{ - type Output = (S::Output, T::Output); - fn build(&self) -> Self::Output { (self.0.build().to_static().upcast(), self.1.build()) } -} - -impl Factory for () { - type Output = (); - fn build(&self) -> Self::Output { () } -} - -fn main() { - // More parens, more time. - let it = ((((((((((),()),()),()),()),()),()),()),()),()); - it.build(); -} diff --git a/tests/ui/ptr-coercion-rpass.rs b/tests/ui/ptr-coercion-rpass.rs deleted file mode 100644 index 8cc4120328e45..0000000000000 --- a/tests/ui/ptr-coercion-rpass.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ run-pass - -#![allow(unused_variables)] -// Test coercions between pointers which don't do anything fancy like unsizing. - - -pub fn main() { - // &mut -> & - let x: &mut isize = &mut 42; - let x: &isize = x; - - let x: &isize = &mut 42; - - // & -> *const - let x: &isize = &42; - let x: *const isize = x; - - let x: *const isize = &42; - - // &mut -> *const - let x: &mut isize = &mut 42; - let x: *const isize = x; - - let x: *const isize = &mut 42; - - // *mut -> *const - let x: *mut isize = &mut 42; - let x: *const isize = x; -} diff --git a/tests/ui/query-visibility.rs b/tests/ui/query-visibility.rs deleted file mode 100644 index 84abe875910cc..0000000000000 --- a/tests/ui/query-visibility.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ check-pass -// Check that it doesn't panic when `Input` gets its visibility checked. - -#![crate_type = "lib"] - -pub trait Layer< - /// Hello. - Input, -> {} diff --git a/tests/ui/raw-str.rs b/tests/ui/raw-str.rs deleted file mode 100644 index 230184032952e..0000000000000 Binary files a/tests/ui/raw-str.rs and /dev/null differ diff --git a/tests/ui/reassign-ref-mut.rs b/tests/ui/reassign-ref-mut.rs deleted file mode 100644 index d6d41e959d9af..0000000000000 --- a/tests/ui/reassign-ref-mut.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Tests how we behave when the user attempts to mutate an immutable -// binding that was introduced by either `ref` or `ref mut` -// patterns. -// -// Such bindings cannot be made mutable via the mere addition of the -// `mut` keyword, and thus we want to check that the compiler does not -// suggest doing so. - -fn main() { - let (mut one_two, mut three_four) = ((1, 2), (3, 4)); - let &mut (ref a, ref mut b) = &mut one_two; - a = &three_four.0; - //~^ ERROR cannot assign twice to immutable variable `a` [E0384] - b = &mut three_four.1; - //~^ ERROR cannot assign twice to immutable variable `b` [E0384] -} diff --git a/tests/ui/resolve/resolve-same-name-struct.rs b/tests/ui/resolve/resolve-same-name-struct.rs new file mode 100644 index 0000000000000..1bea0938e3da0 --- /dev/null +++ b/tests/ui/resolve/resolve-same-name-struct.rs @@ -0,0 +1,29 @@ +//! Test that name resolution works correctly when a struct and its constructor +//! function have the same name within a nested scope. This checks that the +//! compiler can distinguish between type names and value names in the same +//! namespace. + +//@ run-pass + +struct Point { + i: isize, +} + +impl Point { + fn get_value(&self) -> isize { + return 37; + } +} + +// Constructor function with the same name as the struct +#[allow(non_snake_case)] +fn Point(i: isize) -> Point { + Point { i } +} + +pub fn main() { + // Test that we can use the constructor function + let point = Point(42); + assert_eq!(point.i, 42); + assert_eq!(point.get_value(), 37); +} diff --git a/tests/ui/shadow-bool.rs b/tests/ui/shadowed/primitive-type-shadowing.rs similarity index 57% rename from tests/ui/shadow-bool.rs rename to tests/ui/shadowed/primitive-type-shadowing.rs index 8cba2c1710b44..fdcb4246a82fc 100644 --- a/tests/ui/shadow-bool.rs +++ b/tests/ui/shadowed/primitive-type-shadowing.rs @@ -1,3 +1,6 @@ +//! Check that a primitive type can be shadowed by a user-defined type, and the primitive type +//! can still be referenced using its fully qualified path (e.g., `core::primitive::bool`). + //@ check-pass mod bar { diff --git a/tests/ui/shadowed-use-visibility.rs b/tests/ui/shadowed/use-shadows-reexport.rs similarity index 62% rename from tests/ui/shadowed-use-visibility.rs rename to tests/ui/shadowed/use-shadows-reexport.rs index 5ce4103b55970..d220e4b406be8 100644 --- a/tests/ui/shadowed-use-visibility.rs +++ b/tests/ui/shadowed/use-shadows-reexport.rs @@ -1,3 +1,5 @@ +//! Check that a local `use` declaration can shadow a re-exported item within the same module. + //@ run-pass #![allow(unused_imports)] diff --git a/tests/ui/short-error-format.stderr b/tests/ui/short-error-format.stderr deleted file mode 100644 index 1a4a6d4df88e7..0000000000000 --- a/tests/ui/short-error-format.stderr +++ /dev/null @@ -1,3 +0,0 @@ -$DIR/short-error-format.rs:6:9: error[E0308]: mismatched types: expected `u32`, found `String` -$DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32` -error: aborting due to 2 previous errors diff --git a/tests/ui/sized-borrowed-pointer.rs b/tests/ui/sized-borrowed-pointer.rs deleted file mode 100644 index bd213c067db5d..0000000000000 --- a/tests/ui/sized-borrowed-pointer.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -// Possibly-dynamic size of typaram should be cleared at pointer boundary. - - -fn bar() { } -fn foo() { bar::<&T>() } -pub fn main() { } diff --git a/tests/ui/sized-cycle-note.rs b/tests/ui/sized-cycle-note.rs deleted file mode 100644 index 766a5fa0de3dc..0000000000000 --- a/tests/ui/sized-cycle-note.rs +++ /dev/null @@ -1,7 +0,0 @@ -struct Baz { q: Option } -//~^ ERROR recursive types `Baz` and `Foo` have infinite size -struct Foo { q: Option } - -impl Foo { fn bar(&self) {} } - -fn main() {} diff --git a/tests/ui/sized-cycle-note.stderr b/tests/ui/sized-cycle-note.stderr deleted file mode 100644 index 21e54c12fedad..0000000000000 --- a/tests/ui/sized-cycle-note.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0072]: recursive types `Baz` and `Foo` have infinite size - --> $DIR/sized-cycle-note.rs:1:1 - | -LL | struct Baz { q: Option } - | ^^^^^^^^^^ --- recursive without indirection -LL | -LL | struct Foo { q: Option } - | ^^^^^^^^^^ --- recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle - | -LL ~ struct Baz { q: Option> } -LL | -LL ~ struct Foo { q: Option> } - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/sized-owned-pointer.rs b/tests/ui/sized-owned-pointer.rs deleted file mode 100644 index b35c0f91abd2c..0000000000000 --- a/tests/ui/sized-owned-pointer.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -// Possibly-dynamic size of typaram should be cleared at pointer boundary. - - - -fn bar() { } -fn foo() { bar::>() } -pub fn main() { } diff --git a/tests/ui/sized/recursive-type-infinite-size.rs b/tests/ui/sized/recursive-type-infinite-size.rs new file mode 100644 index 0000000000000..5cd8e89557393 --- /dev/null +++ b/tests/ui/sized/recursive-type-infinite-size.rs @@ -0,0 +1,16 @@ +//! Check for compilation errors when recursive types are defined in a way +//! that leads to an infinite size. + +struct Baz { + //~^ ERROR recursive types `Baz` and `Foo` have infinite size + q: Option, +} +struct Foo { + q: Option, +} + +impl Foo { + fn bar(&self) {} +} + +fn main() {} diff --git a/tests/ui/sized/recursive-type-infinite-size.stderr b/tests/ui/sized/recursive-type-infinite-size.stderr new file mode 100644 index 0000000000000..98ac36c4bb6bb --- /dev/null +++ b/tests/ui/sized/recursive-type-infinite-size.stderr @@ -0,0 +1,25 @@ +error[E0072]: recursive types `Baz` and `Foo` have infinite size + --> $DIR/recursive-type-infinite-size.rs:4:1 + | +LL | struct Baz { + | ^^^^^^^^^^ +LL | +LL | q: Option, + | --- recursive without indirection +LL | } +LL | struct Foo { + | ^^^^^^^^^^ +LL | q: Option, + | --- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL ~ q: Option>, +LL | } +LL | struct Foo { +LL ~ q: Option>, + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/sized/sized-box-unsized-content.rs b/tests/ui/sized/sized-box-unsized-content.rs new file mode 100644 index 0000000000000..9cc202a1582fd --- /dev/null +++ b/tests/ui/sized/sized-box-unsized-content.rs @@ -0,0 +1,11 @@ +//! Check that `Box` is `Sized`, even when `T` is a dynamically sized type. + +//@ run-pass + +#![allow(dead_code)] + +fn bar() {} +fn foo() { + bar::>() +} +pub fn main() {} diff --git a/tests/ui/sized/sized-reference-to-unsized.rs b/tests/ui/sized/sized-reference-to-unsized.rs new file mode 100644 index 0000000000000..ac2934d8fe646 --- /dev/null +++ b/tests/ui/sized/sized-reference-to-unsized.rs @@ -0,0 +1,11 @@ +//! Check that a reference to a potentially unsized type (`&T`) is itself considered `Sized`. + +//@ run-pass + +#![allow(dead_code)] + +fn bar() {} +fn foo() { + bar::<&T>() +} +pub fn main() {} diff --git a/tests/ui/stable-addr-of.rs b/tests/ui/stable-addr-of.rs deleted file mode 100644 index e330a4853ce03..0000000000000 --- a/tests/ui/stable-addr-of.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -// Issue #2040 - - -pub fn main() { - let foo: isize = 1; - assert_eq!(&foo as *const isize, &foo as *const isize); -} diff --git a/tests/ui/paths-containing-nul.rs b/tests/ui/std/fs-nul-byte-paths.rs similarity index 80% rename from tests/ui/paths-containing-nul.rs rename to tests/ui/std/fs-nul-byte-paths.rs index 5c37980127db1..790123623474d 100644 --- a/tests/ui/paths-containing-nul.rs +++ b/tests/ui/std/fs-nul-byte-paths.rs @@ -1,18 +1,22 @@ -//@ run-pass +//! Test that `std::fs` functions properly reject paths containing NUL bytes. +//@ run-pass #![allow(deprecated)] //@ ignore-wasm32 no cwd //@ ignore-sgx no files -use std::fs; -use std::io; +use std::{fs, io}; fn assert_invalid_input(on: &str, result: io::Result) { fn inner(on: &str, result: io::Result<()>) { match result { Ok(()) => panic!("{} didn't return an error on a path with NUL", on), - Err(e) => assert!(e.kind() == io::ErrorKind::InvalidInput, - "{} returned a strange {:?} on a path with NUL", on, e.kind()), + Err(e) => assert!( + e.kind() == io::ErrorKind::InvalidInput, + "{} returned a strange {:?} on a path with NUL", + on, + e.kind() + ), } } inner(on, result.map(drop)) @@ -43,6 +47,8 @@ fn main() { assert_invalid_input("remove_dir", fs::remove_dir("\0")); assert_invalid_input("remove_dir_all", fs::remove_dir_all("\0")); assert_invalid_input("read_dir", fs::read_dir("\0")); - assert_invalid_input("set_permissions", - fs::set_permissions("\0", fs::metadata(".").unwrap().permissions())); + assert_invalid_input( + "set_permissions", + fs::set_permissions("\0", fs::metadata(".").unwrap().permissions()), + ); } diff --git a/tests/ui/nul-characters.rs b/tests/ui/str/nul-char-equivalence.rs similarity index 79% rename from tests/ui/nul-characters.rs rename to tests/ui/str/nul-char-equivalence.rs index eb83f440d3e03..2d4110de6812b 100644 --- a/tests/ui/nul-characters.rs +++ b/tests/ui/str/nul-char-equivalence.rs @@ -1,7 +1,8 @@ +//! Checks that different NUL character representations are equivalent in strings and chars. + //@ run-pass -pub fn main() -{ +pub fn main() { let all_nuls1 = "\0\x00\u{0}\u{0}"; let all_nuls2 = "\u{0}\u{0}\x00\0"; let all_nuls3 = "\u{0}\u{0}\x00\0"; @@ -17,11 +18,9 @@ pub fn main() assert_eq!(all_nuls3, all_nuls4); // all extracted characters in all_nuls are equivalent to each other - for c1 in all_nuls1.chars() - { - for c2 in all_nuls1.chars() - { - assert_eq!(c1,c2); + for c1 in all_nuls1.chars() { + for c2 in all_nuls1.chars() { + assert_eq!(c1, c2); } } diff --git a/tests/ui/std-uncopyable-atomics.rs b/tests/ui/sync/atomic-types-not-copyable.rs similarity index 71% rename from tests/ui/std-uncopyable-atomics.rs rename to tests/ui/sync/atomic-types-not-copyable.rs index d85864ecac285..d96414676ee66 100644 --- a/tests/ui/std-uncopyable-atomics.rs +++ b/tests/ui/sync/atomic-types-not-copyable.rs @@ -1,8 +1,10 @@ -// Issue #8380 +//! Check that atomic types from `std::sync::atomic` are not `Copy` +//! and cannot be moved out of a shared reference. +//! +//! Regression test for . - -use std::sync::atomic::*; use std::ptr; +use std::sync::atomic::*; fn main() { let x = AtomicBool::new(false); diff --git a/tests/ui/std-uncopyable-atomics.stderr b/tests/ui/sync/atomic-types-not-copyable.stderr similarity index 88% rename from tests/ui/std-uncopyable-atomics.stderr rename to tests/ui/sync/atomic-types-not-copyable.stderr index 8c5d0b9609627..05103f5d8f265 100644 --- a/tests/ui/std-uncopyable-atomics.stderr +++ b/tests/ui/sync/atomic-types-not-copyable.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:9:13 + --> $DIR/atomic-types-not-copyable.rs:11:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait @@ -11,7 +11,7 @@ LL + let x = &x; | error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:11:13 + --> $DIR/atomic-types-not-copyable.rs:13:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicIsize`, which does not implement the `Copy` trait @@ -23,7 +23,7 @@ LL + let x = &x; | error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:13:13 + --> $DIR/atomic-types-not-copyable.rs:15:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait @@ -35,7 +35,7 @@ LL + let x = &x; | error[E0507]: cannot move out of a shared reference - --> $DIR/std-uncopyable-atomics.rs:15:13 + --> $DIR/atomic-types-not-copyable.rs:17:13 | LL | let x = *&x; | ^^^ move occurs because value has type `std::sync::atomic::AtomicPtr`, which does not implement the `Copy` trait diff --git a/tests/ui/sse2.rs b/tests/ui/target-feature/target-feature-detection.rs similarity index 55% rename from tests/ui/sse2.rs rename to tests/ui/target-feature/target-feature-detection.rs index a1894cc03dbc5..3404bfbe782ac 100644 --- a/tests/ui/sse2.rs +++ b/tests/ui/target-feature/target-feature-detection.rs @@ -1,3 +1,6 @@ +//! Check that `cfg!(target_feature = "...")` correctly detects available CPU features, +//! specifically `sse2` on x86/x86_64 platforms, and correctly reports absent features. + //@ run-pass #![allow(stable_features)] @@ -10,17 +13,23 @@ fn main() { Ok(s) => { // Skip this tests on i586-unknown-linux-gnu where sse2 is disabled if s.contains("i586") { - return + return; } } Err(_) => return, } if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { - assert!(cfg!(target_feature = "sse2"), - "SSE2 was not detected as available on an x86 platform"); + assert!( + cfg!(target_feature = "sse2"), + "SSE2 was not detected as available on an x86 platform" + ); } // check a negative case too -- certainly not enabled by default #[expect(unexpected_cfgs)] - { assert!(cfg!(not(target_feature = "ferris_wheel")), - "🎡 shouldn't be detected as available by default on any platform") }; + { + assert!( + cfg!(not(target_feature = "ferris_wheel")), + "🎡 shouldn't be detected as available by default on any platform" + ) + }; } diff --git a/tests/ui/opt-in-copy.rs b/tests/ui/traits/copy-requires-all-fields-copy.rs similarity index 82% rename from tests/ui/opt-in-copy.rs rename to tests/ui/traits/copy-requires-all-fields-copy.rs index d0257b5745d8b..8c829a7382b3e 100644 --- a/tests/ui/opt-in-copy.rs +++ b/tests/ui/traits/copy-requires-all-fields-copy.rs @@ -1,3 +1,5 @@ +//! Test that `Copy` cannot be implemented if any field doesn't implement `Copy`. + struct CantCopyThis; struct IWantToCopyThis { diff --git a/tests/ui/opt-in-copy.stderr b/tests/ui/traits/copy-requires-all-fields-copy.stderr similarity index 86% rename from tests/ui/opt-in-copy.stderr rename to tests/ui/traits/copy-requires-all-fields-copy.stderr index 258ff16e6e485..1a9e1ada36637 100644 --- a/tests/ui/opt-in-copy.stderr +++ b/tests/ui/traits/copy-requires-all-fields-copy.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/opt-in-copy.rs:7:15 + --> $DIR/copy-requires-all-fields-copy.rs:9:15 | LL | but_i_cant: CantCopyThis, | ------------------------ this field does not implement `Copy` @@ -8,7 +8,7 @@ LL | impl Copy for IWantToCopyThis {} | ^^^^^^^^^^^^^^^ error[E0204]: the trait `Copy` cannot be implemented for this type - --> $DIR/opt-in-copy.rs:19:15 + --> $DIR/copy-requires-all-fields-copy.rs:21:15 | LL | ButICant(CantCopyThisEither), | ------------------ this field does not implement `Copy` diff --git a/tests/ui/string-box-error.rs b/tests/ui/traits/error-trait-object-from-string.rs similarity index 71% rename from tests/ui/string-box-error.rs rename to tests/ui/traits/error-trait-object-from-string.rs index 9a7cd81ee0453..896f164a04d46 100644 --- a/tests/ui/string-box-error.rs +++ b/tests/ui/traits/error-trait-object-from-string.rs @@ -1,6 +1,7 @@ +//! Check that `String` and `&str` can be converted into `Box` and +//! `Box` trait objects + //@ run-pass -// Ensure that both `Box` and `Box` can be -// obtained from `String`. use std::error::Error; diff --git a/tests/ui/object-pointer-types.rs b/tests/ui/traits/trait-object-method-receiver-rules.rs similarity index 81% rename from tests/ui/object-pointer-types.rs rename to tests/ui/traits/trait-object-method-receiver-rules.rs index 760a50e5b7972..383e59c131a14 100644 --- a/tests/ui/object-pointer-types.rs +++ b/tests/ui/traits/trait-object-method-receiver-rules.rs @@ -1,7 +1,8 @@ +//! Checks that method availability rules for trait objects depend on receiver type. + trait Foo { fn borrowed(&self); fn borrowed_mut(&mut self); - fn owned(self: Box); } @@ -20,7 +21,7 @@ fn borrowed_mut_receiver(x: &mut dyn Foo) { fn owned_receiver(x: Box) { x.borrowed(); x.borrowed_mut(); // See [1] - x.managed(); //~ ERROR no method named `managed` found + x.managed(); //~ ERROR no method named `managed` found x.owned(); } diff --git a/tests/ui/object-pointer-types.stderr b/tests/ui/traits/trait-object-method-receiver-rules.stderr similarity index 86% rename from tests/ui/object-pointer-types.stderr rename to tests/ui/traits/trait-object-method-receiver-rules.stderr index 72b290f2ad9f8..83b61a2e6b52e 100644 --- a/tests/ui/object-pointer-types.stderr +++ b/tests/ui/traits/trait-object-method-receiver-rules.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope - --> $DIR/object-pointer-types.rs:11:7 + --> $DIR/trait-object-method-receiver-rules.rs:12:7 | LL | fn owned(self: Box); | --------- the method might not be found because of this arbitrary self type @@ -13,7 +13,7 @@ LL | x.to_owned(); | +++ error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope - --> $DIR/object-pointer-types.rs:17:7 + --> $DIR/trait-object-method-receiver-rules.rs:18:7 | LL | fn owned(self: Box); | --------- the method might not be found because of this arbitrary self type @@ -22,7 +22,7 @@ LL | x.owned(); | ^^^^^ method not found in `&mut dyn Foo` error[E0599]: no method named `managed` found for struct `Box<(dyn Foo + 'static)>` in the current scope - --> $DIR/object-pointer-types.rs:23:7 + --> $DIR/trait-object-method-receiver-rules.rs:24:7 | LL | x.managed(); | ^^^^^^^ method not found in `Box<(dyn Foo + 'static)>` diff --git a/tests/ui/objects-coerce-freeze-borrored.rs b/tests/ui/traits/trait-object-mut-to-shared-coercion.rs similarity index 88% rename from tests/ui/objects-coerce-freeze-borrored.rs rename to tests/ui/traits/trait-object-mut-to-shared-coercion.rs index e122bb9938061..26b5cc6d2dfcb 100644 --- a/tests/ui/objects-coerce-freeze-borrored.rs +++ b/tests/ui/traits/trait-object-mut-to-shared-coercion.rs @@ -1,6 +1,6 @@ -//@ run-pass -// Test that we can coerce an `@Object` to an `&Object` +//! Tests that coercion from `&mut dyn Trait` to `&dyn Trait` works correctly. +//@ run-pass trait Foo { fn foo(&self) -> usize; diff --git a/tests/ui/type-inference/direct-self-reference-occurs-check.rs b/tests/ui/type-inference/direct-self-reference-occurs-check.rs new file mode 100644 index 0000000000000..6e3d8251fc4f8 --- /dev/null +++ b/tests/ui/type-inference/direct-self-reference-occurs-check.rs @@ -0,0 +1,9 @@ +//! Test that occurs check prevents direct self-reference in variable assignment. +//! +//! Regression test for . + +fn main() { + let f; + f = Box::new(f); + //~^ ERROR overflow assigning `Box<_>` to `_` +} diff --git a/tests/ui/occurs-check.stderr b/tests/ui/type-inference/direct-self-reference-occurs-check.stderr similarity index 79% rename from tests/ui/occurs-check.stderr rename to tests/ui/type-inference/direct-self-reference-occurs-check.stderr index ea7c541abc135..6c522ffac1f7a 100644 --- a/tests/ui/occurs-check.stderr +++ b/tests/ui/type-inference/direct-self-reference-occurs-check.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow assigning `Box<_>` to `_` - --> $DIR/occurs-check.rs:3:18 + --> $DIR/direct-self-reference-occurs-check.rs:7:18 | LL | f = Box::new(f); | ^ diff --git a/tests/ui/type-inference/enum-self-reference-occurs-check.rs b/tests/ui/type-inference/enum-self-reference-occurs-check.rs new file mode 100644 index 0000000000000..2905868b8bfa9 --- /dev/null +++ b/tests/ui/type-inference/enum-self-reference-occurs-check.rs @@ -0,0 +1,16 @@ +//! Test that occurs check prevents infinite types with enum self-references. +//! +//! Regression test for . + +enum Clam { + A(T), +} + +fn main() { + let c; + c = Clam::A(c); + //~^ ERROR overflow assigning `Clam<_>` to `_` + match c { + Clam::A::(_) => {} + } +} diff --git a/tests/ui/occurs-check-3.stderr b/tests/ui/type-inference/enum-self-reference-occurs-check.stderr similarity index 80% rename from tests/ui/occurs-check-3.stderr rename to tests/ui/type-inference/enum-self-reference-occurs-check.stderr index eb05c94957c98..3239be51a1766 100644 --- a/tests/ui/occurs-check-3.stderr +++ b/tests/ui/type-inference/enum-self-reference-occurs-check.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow assigning `Clam<_>` to `_` - --> $DIR/occurs-check-3.rs:6:17 + --> $DIR/enum-self-reference-occurs-check.rs:11:17 | LL | c = Clam::A(c); | ^ diff --git a/tests/ui/type-inference/infinite-type-occurs-check.rs b/tests/ui/type-inference/infinite-type-occurs-check.rs new file mode 100644 index 0000000000000..b353824e931d4 --- /dev/null +++ b/tests/ui/type-inference/infinite-type-occurs-check.rs @@ -0,0 +1,12 @@ +//! Test that occurs check prevents infinite types during type inference. +//! +//! Regression test for . + +fn main() { + let f; + let g; + + g = f; + //~^ ERROR overflow assigning `Box<_>` to `_` + f = Box::new(g); +} diff --git a/tests/ui/occurs-check-2.stderr b/tests/ui/type-inference/infinite-type-occurs-check.stderr similarity index 81% rename from tests/ui/occurs-check-2.stderr rename to tests/ui/type-inference/infinite-type-occurs-check.stderr index 5f296967f30d8..9cb8bb917962e 100644 --- a/tests/ui/occurs-check-2.stderr +++ b/tests/ui/type-inference/infinite-type-occurs-check.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow assigning `Box<_>` to `_` - --> $DIR/occurs-check-2.rs:6:9 + --> $DIR/infinite-type-occurs-check.rs:9:9 | LL | g = f; | ^ diff --git a/tests/ui/type/inherent-impl-primitive-types-error.rs b/tests/ui/type/inherent-impl-primitive-types-error.rs new file mode 100644 index 0000000000000..88b8b9da56b8e --- /dev/null +++ b/tests/ui/type/inherent-impl-primitive-types-error.rs @@ -0,0 +1,28 @@ +//! Test that inherent impl blocks cannot be defined for primitive types + +impl u8 { + //~^ ERROR: cannot define inherent `impl` for primitive types + pub const B: u8 = 0; +} + +impl str { + //~^ ERROR: cannot define inherent `impl` for primitive types + fn foo() {} + fn bar(self) {} //~ ERROR: size for values of type `str` cannot be known +} + +impl char { + //~^ ERROR: cannot define inherent `impl` for primitive types + pub const B: u8 = 0; + pub const C: u8 = 0; + fn foo() {} + fn bar(self) {} +} + +struct MyType; +impl &MyType { + //~^ ERROR: cannot define inherent `impl` for primitive types + pub fn for_ref(self) {} +} + +fn main() {} diff --git a/tests/ui/kinds-of-primitive-impl.stderr b/tests/ui/type/inherent-impl-primitive-types-error.stderr similarity index 83% rename from tests/ui/kinds-of-primitive-impl.stderr rename to tests/ui/type/inherent-impl-primitive-types-error.stderr index 1c8c417e88c1f..5b79521a35e77 100644 --- a/tests/ui/kinds-of-primitive-impl.stderr +++ b/tests/ui/type/inherent-impl-primitive-types-error.stderr @@ -1,5 +1,5 @@ error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:1:1 + --> $DIR/inherent-impl-primitive-types-error.rs:3:1 | LL | impl u8 { | ^^^^^^^ @@ -7,7 +7,7 @@ LL | impl u8 { = help: consider using an extension trait instead error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:6:1 + --> $DIR/inherent-impl-primitive-types-error.rs:8:1 | LL | impl str { | ^^^^^^^^ @@ -15,7 +15,7 @@ LL | impl str { = help: consider using an extension trait instead error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:12:1 + --> $DIR/inherent-impl-primitive-types-error.rs:14:1 | LL | impl char { | ^^^^^^^^^ @@ -23,7 +23,7 @@ LL | impl char { = help: consider using an extension trait instead error[E0390]: cannot define inherent `impl` for primitive types - --> $DIR/kinds-of-primitive-impl.rs:21:1 + --> $DIR/inherent-impl-primitive-types-error.rs:23:1 | LL | impl &MyType { | ^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | impl &MyType { = note: you could also try moving the reference to uses of `MyType` (such as `self`) within the implementation error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/kinds-of-primitive-impl.rs:9:12 + --> $DIR/inherent-impl-primitive-types-error.rs:11:12 | LL | fn bar(self) {} | ^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/type/mutually-recursive-types.rs b/tests/ui/type/mutually-recursive-types.rs new file mode 100644 index 0000000000000..5472e1582218e --- /dev/null +++ b/tests/ui/type/mutually-recursive-types.rs @@ -0,0 +1,47 @@ +//! Test that mutually recursive type definitions are properly handled by the compiler. +//! This checks that types can reference each other in their definitions through +//! `Box` indirection, creating cycles in the type dependency graph. + +//@ run-pass + +#[derive(Debug, PartialEq)] +enum Colour { + Red, + Green, + Blue, +} + +#[derive(Debug, PartialEq)] +enum Tree { + Children(Box), + Leaf(Colour), +} + +#[derive(Debug, PartialEq)] +enum List { + Cons(Box, Box), + Nil, +} + +#[derive(Debug, PartialEq)] +enum SmallList { + Kons(isize, Box), + Neel, +} + +pub fn main() { + // Construct and test all variants of Colour + let _ = Tree::Leaf(Colour::Red); + + let _ = Tree::Leaf(Colour::Green); + + let _ = Tree::Leaf(Colour::Blue); + + let _ = List::Nil; + + let _ = Tree::Children(Box::new(List::Nil)); + + let _ = List::Cons(Box::new(Tree::Leaf(Colour::Blue)), Box::new(List::Nil)); + + let _ = SmallList::Kons(42, Box::new(SmallList::Neel)); +} diff --git a/tests/ui/typeck/nested-generic-traits-performance.rs b/tests/ui/typeck/nested-generic-traits-performance.rs new file mode 100644 index 0000000000000..e029228c1b2ef --- /dev/null +++ b/tests/ui/typeck/nested-generic-traits-performance.rs @@ -0,0 +1,82 @@ +//! Test that deeply nested generic traits with complex bounds +//! don't cause excessive memory usage during type checking. +//! +//! Regression test for . + +//@ run-pass + +pub trait Upcast { + fn upcast(self) -> T; +} + +impl Upcast<(T1, T2)> for (S1, S2) +where + S1: Upcast, + S2: Upcast, +{ + fn upcast(self) -> (T1, T2) { + (self.0.upcast(), self.1.upcast()) + } +} + +impl Upcast<()> for () { + fn upcast(self) -> () { + () + } +} + +pub trait ToStatic { + type Static: 'static; + fn to_static(self) -> Self::Static + where + Self: Sized; +} + +impl ToStatic for (T, U) +where + T: ToStatic, + U: ToStatic, +{ + type Static = (T::Static, U::Static); + fn to_static(self) -> Self::Static { + (self.0.to_static(), self.1.to_static()) + } +} + +impl ToStatic for () { + type Static = (); + fn to_static(self) -> () { + () + } +} + +trait Factory { + type Output; + fn build(&self) -> Self::Output; +} + +impl Factory for (S, T) +where + S: Factory, + T: Factory, + S::Output: ToStatic, + ::Static: Upcast, +{ + type Output = (S::Output, T::Output); + fn build(&self) -> Self::Output { + (self.0.build().to_static().upcast(), self.1.build()) + } +} + +impl Factory for () { + type Output = (); + fn build(&self) -> Self::Output { + () + } +} + +fn main() { + // Deeply nested tuple to trigger the original performance issue + let it = ((((((((((), ()), ()), ()), ()), ()), ()), ()), ()), ()); + it.build(); +}