Auto merge of #143473 - workingjubilee:rollup-bxie7zg, r=scottmcm

Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#142440 (`tests/ui`: A New Order [14/N])
 - rust-lang/rust#143040 (Add `const Rem`)
 - rust-lang/rust#143086 (Update poison.rs to fix the typo (sys->sync))
 - rust-lang/rust#143202 (`tests/ui`: A New Order [18/N])
 - rust-lang/rust#143296 (`tests/ui`: A New Order [21/N])
 - rust-lang/rust#143297 (`tests/ui`: A New Order [22/N])
 - rust-lang/rust#143299 (`tests/ui`: A New Order [24/N])
 - rust-lang/rust#143300 (`tests/ui`: A New Order [25/N])
 - rust-lang/rust#143397 (test passing a `VaList` from rust to C)
 - rust-lang/rust#143410 (Block SIMD in transmute_immediate; delete `OperandValueKind`)
 - rust-lang/rust#143452 (Fix CLI completion check in `tidy`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-07-05 09:37:08 +00:00
commit fd9ca711a3
134 changed files with 1256 additions and 948 deletions

View file

@ -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<V, abi::Scalar>> {
};
let mut update = |tgt: &mut Result<V, abi::Scalar>, 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);
};

View file

@ -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<Bx::Value>> {
) -> OperandValue<Bx::Value> {
// 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`.
///
/// `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>>(
/// This is expected to be in *immediate* form, as seen in [`OperandValue::Immediate`]
/// or [`OperandValue::Pair`] (so `i1` for bools, not `i8`, for example).
///
/// 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::<u32, NonZeroU32>(x) == 0
// since it's never passed to something with parameter metadata (especially

View file

@ -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]

View file

@ -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
//!

View file

@ -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<'_> {

View file

@ -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"

View file

@ -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<G: clap_complete::Generator>(shell: G, path: &Path) -> Option<String> {
pub fn get_completion(shell: &dyn Generator, path: &Path) -> Option<String> {
let mut cmd = Flags::command();
let current = if !path.exists() {
String::new()
@ -662,7 +663,12 @@ pub fn get_completion<G: clap_complete::Generator>(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;
}

View file

@ -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

View file

@ -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')

View file

@ -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' \

View file

@ -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

View file

@ -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)
}

View file

@ -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);

View file

@ -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) }
}

View file

@ -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"))]

View file

@ -41,9 +41,6 @@ pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
// 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<u8>) -> Vec<Wrapper<u8>> {
// 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<Wrapper<u8>>) -> Vec<u8> {
// 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<Foo> {
// 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<Bar>) -> 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<Baz>) -> 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<Wrapper<String>>) -> Vec<String> {
// 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<String>) -> Vec<Wrapper<String>> {
// 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()

View file

@ -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::<c_longlong>() == 1);
continue_if!(ap.arg::<c_int>() == 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::<c_int>() == -1);
continue_if!(ap.arg::<c_int>() == '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::<c_double>().floor() == 3.14f64.floor());
continue_if!(ap.arg::<c_long>() == 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::<c_double>().floor() == 6.28f64.floor());
continue_if!(ap.arg::<c_int>() == 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::<c_int>() == 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::<c_double>().floor() == 3.14f64.floor());
continue_if!(ap.arg::<c_long>() == 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::<c_int>() == 1);
continue_if!(ap.arg::<c_int>() == 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::<c_double>() == 1.0);
continue_if!(ap.arg::<c_double>() == 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::<c_double>() == 1.0);
continue_if!(ap.arg::<c_int>() == 1);
@ -148,3 +149,42 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
continue_if!(ap.arg::<c_double>() == 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) }
}

View file

@ -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;
}

View file

@ -1,13 +1,13 @@
//! Sanity check for out-of-bounds read caused by copying the entire original buffer on shrink.
//!
//! Regression test for: <https://github.com/rust-lang/rust/issues/16687>
//@ 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() {

View file

@ -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<Output = u32> + '_ {
//~^ ERROR `u32` is not a future
*x

View file

@ -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<Output = u32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future

View file

@ -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

View file

@ -1,9 +1,9 @@
// Ensure that auto trait checks `T` when it encounters a `PhantomData<T>` field, instead of
// checking the `PhantomData<T>` type itself (which almost always implements an auto trait).
//! Ensure that auto trait checks `T` when it encounters a `PhantomData<T>` field, instead of
//! checking the `PhantomData<T>` type itself (which almost always implements an auto trait).
#![feature(auto_traits)]
use std::marker::{PhantomData};
use std::marker::PhantomData;
unsafe auto trait Zen {}

View file

@ -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: Zen>(_: T) {}
| ^^^ required by this bound in `is_zen`
@ -29,7 +29,7 @@ LL | fn not_sync<T: std::marker::Sync>(x: Guard<T>) {
| +++++++++++++++++++
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<Guard<'_, T>>`
--> $DIR/phantom-auto-trait.rs:16:8
--> $DIR/auto-trait-phantom-data-bounds.rs:16:8
|
LL | struct Nested<T>(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: Zen>(_: T) {}
| ^^^ required by this bound in `is_zen`

View file

@ -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
}
);
}

View file

@ -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;

View file

@ -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 <https://github.com/rust-lang/rust/pull/34216>.
#[cfg_attr(all(), cfg_attr(all(), cfg(false)))]
fn f() {}
fn main() {
f() //~ ERROR cannot find function `f` in this scope
}

View file

@ -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

View file

@ -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<isize>,
}
pub fn main() {
fn invoke<F>(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()));
}

View file

@ -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<T, F>(s: String, mut f: F) -> T
where
F: FnMut(String) -> T
{
fn g<T, F>(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);
}

View file

@ -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;

View file

@ -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;
| ^

View file

@ -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<isize>,
}
fn foo() -> Box<dyn FnMut() -> 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);
}

View file

@ -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<F:FnOnce()>(blk: F) {
fn foo<F: FnOnce()>(blk: F) {
blk();
blk(); //~ ERROR use of moved value
}
fn main() {
let x = Arc::new(true);
foo(move|| {
foo(move || {
assert!(*x);
drop(x);
});

View file

@ -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<F:FnOnce()>(blk: F) {
| --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
LL | fn foo<F: FnOnce()>(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<F:FnOnce()>(blk: F) {
| ^^^^^^^^ `F` is made to be an `FnOnce` closure here
LL | fn foo<F: FnOnce()>(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

View file

@ -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 <https://github.com/rust-lang/rust/issues/34793>.
//! See also <https://github.com/rust-lang/rust/pull/34830>.
//@ 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);
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,11 @@
//! Check that taking the address of a stack variable with `&`
//! yields a stable and comparable pointer.
//!
//! Regression test for <https://github.com/rust-lang/rust/issues/2040>.
//@ run-pass
pub fn main() {
let foo: isize = 1;
assert_eq!(&foo as *const isize, &foo as *const isize);
}

View file

@ -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<T> 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);
}

View file

@ -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;

View file

@ -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) {}

View file

@ -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

View file

@ -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<isize>) -> r<'_> {
r {
i: i
}
r { i }
}
pub fn main() {

View file

@ -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<isize>,
i: &'a Cell<isize>,
}
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<isize>) -> 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);
}

View file

@ -1,15 +1,15 @@
//! Checks clean diagnostics for argument count mismatches without unrelated errors.
//!
//! `delegate!` part related: <https://github.com/rust-lang/rust/pull/140591>
//@ 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);

View file

@ -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 | <Self>::$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 | <Self>::$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) {
| ^^^ ------ ------ ------

View file

@ -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<isize>) {
*y = 5;
assert_eq!(*y, 5);
}
fn g() {
let frob = |mut q: Box<isize>| {
*q = 2;
assert_eq!(*q, 2);
};
let w = Box::new(37);
frob(w);
}
pub fn main() {
let z = Box::new(17);
f(z);
g();
}

View file

@ -0,0 +1,14 @@
//! Test that generic parameters from an outer function are not accessible
//! in nested functions.
fn foo<U>(v: Vec<U>) -> 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() {}

View file

@ -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<U>(v: Vec<U> ) -> U {
| - type parameter from outer item
LL | fn hd1(w: [U]) -> U { return w[0]; }
LL | fn foo<U>(v: Vec<U>) -> 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: `<U>`
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<U>(v: Vec<U> ) -> U {
| - type parameter from outer item
LL | fn hd1(w: [U]) -> U { return w[0]; }
LL | fn foo<U>(v: Vec<U>) -> 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: `<U>`

View file

@ -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<T> Seq<T> for Vec<T> {
//~^ ERROR trait takes 0 generic arguments but 1 generic argument

View file

@ -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<T> Seq<T> for Vec<T> {
| ^^^--- help: remove the unnecessary generics
@ -7,13 +7,13 @@ LL | impl<T> Seq<T> for Vec<T> {
| 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<bool> for u32 {
| ^^^------ help: remove the unnecessary generics
@ -21,9 +21,9 @@ LL | impl Seq<bool> 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

View file

@ -1,9 +1,7 @@
//! Regression test for https://github.com/rust-lang/rust/issues/15924
//@ run-pass
#![allow(unused_imports)]
#![allow(unused_must_use)]
use std::fmt;
use std::marker::PhantomData;
trait Encoder {
@ -26,9 +24,8 @@ impl Encoder for JsonEncoder<'_> {
type Error = ();
}
fn encode_json<T: for<'r> Encodable<JsonEncoder<'r>>>(
object: &T,
) -> Result<String, ()> {
// This function uses higher-ranked trait bounds, which previously caused ICE
fn encode_json<T: for<'r> Encodable<JsonEncoder<'r>>>(object: &T) -> Result<String, ()> {
let s = String::new();
{
let mut encoder = JsonEncoder(PhantomData);
@ -37,13 +34,15 @@ fn encode_json<T: for<'r> Encodable<JsonEncoder<'r>>>(
Ok(s)
}
// Structure with HRTB constraint that was problematic
struct Foo<T: for<'a> Encodable<JsonEncoder<'a>>> {
v: T,
}
// Drop implementation that exercises the HRTB bounds
impl<T: for<'a> Encodable<JsonEncoder<'a>>> Drop for Foo<T> {
fn drop(&mut self) {
encode_json(&self.v);
let _ = encode_json(&self.v);
}
}

View file

@ -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::<Vec<_>>();
.collect::<Vec<_>>();
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;

View file

@ -1,3 +1,6 @@
//! Test that print!/println! output to stdout and eprint!/eprintln!
//! output to stderr correctly.
//@ run-pass
//@ needs-subprocess

View file

@ -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);
}

View file

@ -1,16 +0,0 @@
//@ run-pass
#![allow(dead_code)]
mod foo {
pub fn baz() { }
}
mod bar {
pub fn baz() { }
}
pub fn main() { }

View file

@ -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() {}

View file

@ -1,21 +0,0 @@
//@ run-pass
#![allow(dead_code)]
#![allow(unused_parens)]
// Issue #1818
fn lp<T, F>(s: String, mut f: F) -> T where F: FnMut(String) -> T {
while false {
let r = f(s);
return (r);
}
panic!();
}
fn apply<T, F>(s: String, mut f: F) -> T where F: FnMut(String) -> T {
fn g<T, F>(s: String, mut f: F) -> T where F: FnMut(String) -> T {f(s)}
g(s, |v| { let r = f(v); r })
}
pub fn main() {}

View file

@ -1,17 +0,0 @@
//@ run-pass
#![allow(dead_code)]
// Make sure #1399 stays fixed
struct A { a: Box<isize> }
fn foo() -> Box<dyn FnMut() -> 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);
}

View file

@ -1,13 +0,0 @@
//@ run-pass
#![allow(dead_code)]
// Make sure #1399 stays fixed
struct A { a: Box<isize> }
pub fn main() {
fn invoke<F>(f: F) where F: FnOnce() { f(); }
let k: Box<_> = 22.into();
let _u = A {a: k.clone()};
invoke(|| println!("{}", k.clone()) )
}

View file

@ -1,10 +1,20 @@
//! null pointer optimization preserves type sizes.
//!
//! Verifies that Option<T> 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<T> { Thing(isize, T), Nothing((), ((), ()), [i8; 0]) }
enum E<T> {
Thing(isize, T),
Nothing((), ((), ()), [i8; 0]),
}
struct S<T>(isize, T);
// These are macros so we get useful assert messages.
@ -12,20 +22,20 @@ struct S<T>(isize, T);
macro_rules! check_option {
($T:ty) => {
assert_eq!(mem::size_of::<Option<$T>>(), mem::size_of::<$T>());
}
};
}
macro_rules! check_fancy {
($T:ty) => {
assert_eq!(mem::size_of::<E<$T>>(), mem::size_of::<S<$T>>());
}
};
}
macro_rules! check_type {
($T:ty) => {{
check_option!($T);
check_fancy!($T);
}}
}};
}
pub fn main() {

View file

@ -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 <https://coq.inria.fr/doc/language/core/conversion.html#iota-reduction>.
//!
//! This test verifies that null pointer optimization works correctly for both
//! Option<T> 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<T> { Thing(isize, T), #[allow(dead_code)] Nothing((), ((), ()), [i8; 0]) }
enum E<T> {
Thing(isize, T),
#[allow(dead_code)]
Nothing((), ((), ()), [i8; 0]),
}
impl<T> E<T> {
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<isize>);
check_type!("foo".to_string(), String);
check_type!(vec![20, 22], Vec<isize>);
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()));
}

View file

@ -0,0 +1,25 @@
//! Test closure parameter type inference and type mismatch errors.
//!
//! Related to <https://github.com/rust-lang/rust/issues/2093>.
//@ dont-require-annotations: NOTE
fn let_in<T, F>(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`
});
}

View file

@ -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`.

View file

@ -1,4 +1,8 @@
fn unrelated() -> Result<(), std::string::ParseError> { // #57664
//! Regression test for <https://github.com/rust-lang/rust/issues/57664>.
//! 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 {

View file

@ -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}`

View file

@ -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() {}

View file

@ -1,19 +0,0 @@
//@ run-pass
fn f(mut y: Box<isize>) {
*y = 5;
assert_eq!(*y, 5);
}
fn g() {
let frob = |mut q: Box<isize>| { *q = 2; assert_eq!(*q, 2); };
let w = Box::new(37);
frob(w);
}
pub fn main() {
let z = Box::new(17);
f(z);
g();
}

View file

@ -1,15 +0,0 @@
//@ run-pass
#![allow(non_camel_case_types)]
#![allow(dead_code)]
enum colour { red, green, blue, }
enum tree { children(Box<list>), leaf(colour), }
enum list { cons(Box<tree>, Box<list>), nil, }
enum small_list { kons(isize, Box<small_list>), neel, }
pub fn main() { }

View file

@ -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);
}

View file

@ -1,11 +0,0 @@
//@ run-pass
/* This test checks that nested comments are supported
/*
This should not panic
*/
*/
pub fn main() {
}

View file

@ -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

View file

@ -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);
}

View file

@ -1,9 +0,0 @@
fn hd<U>(v: Vec<U> ) -> 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() {}

View file

@ -1,9 +0,0 @@
fn main() {
let f;
let g;
g = f;
//~^ ERROR overflow assigning `Box<_>` to `_`
f = Box::new(g);
}

View file

@ -1,11 +0,0 @@
// From Issue #778
enum Clam<T> { A(T) }
fn main() {
let c;
c = Clam::A(c);
//~^ ERROR overflow assigning `Clam<_>` to `_`
match c {
Clam::A::<isize>(_) => { }
}
}

View file

@ -1,5 +0,0 @@
fn main() {
let f;
f = Box::new(f);
//~^ ERROR overflow assigning `Box<_>` to `_`
}

View file

@ -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);
}

View file

@ -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

View file

@ -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,
>
{
}

View file

@ -0,0 +1,34 @@
//! Test that nested block comments are properly supported by the parser.
//!
//! See <https://github.com/rust-lang/rust/issues/66>.
//@ 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;
}

Binary file not shown.

View file

@ -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`
}

View file

@ -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`

View file

@ -1,13 +0,0 @@
//@ dont-require-annotations: NOTE
fn let_in<T, F>(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`
}

View file

@ -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`.

View file

@ -1,6 +0,0 @@
//@ run-pass
fn main() {
let x = Box::new(0);
assert_eq!(0, *x + { drop(x); let _ = Box::new(main); 0 });
}

View file

@ -1,2 +0,0 @@
//@ compile-flags: --print calling-conventions
//@ build-pass

View file

@ -0,0 +1,4 @@
//! Test that `--print calling-conventions` outputs all supported calling conventions.
//@ compile-flags: --print calling-conventions
//@ build-pass

View file

@ -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<T> {
fn upcast(self) -> T;
}
impl<S1, S2, T1, T2> Upcast<(T1, T2)> for (S1,S2)
where S1: Upcast<T1>,
S2: Upcast<T2>,
{
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<T, U> 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<S,T> Factory for (S, T)
where S: Factory,
T: Factory,
S::Output: ToStatic,
<S::Output as ToStatic>::Static: Upcast<S::Output>,
{
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();
}

View file

@ -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;
}

View file

@ -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,
> {}

Binary file not shown.

View file

@ -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]
}

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