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:
commit
fd9ca711a3
134 changed files with 1256 additions and 948 deletions
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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<'_> {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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' \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"))]
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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 {}
|
||||
|
||||
|
|
@ -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`
|
||||
15
tests/ui/binop/binop-evaluation-order-primitive.rs
Normal file
15
tests/ui/binop/binop-evaluation-order-primitive.rs
Normal 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
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -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;
|
||||
18
tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs
Normal file
18
tests/ui/cfg/nested-cfg-attr-conditional-compilation.rs
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
39
tests/ui/closures/closure-capture-after-clone.rs
Normal file
39
tests/ui/closures/closure-capture-after-clone.rs
Normal 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()));
|
||||
}
|
||||
33
tests/ui/closures/closure-last-use-move.rs
Normal file
33
tests/ui/closures/closure-last-use-move.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
| ^
|
||||
32
tests/ui/closures/closure-upvar-last-use-analysis.rs
Normal file
32
tests/ui/closures/closure-upvar-last-use-analysis.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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
|
||||
|
||||
47
tests/ui/closures/many-closures.rs
Normal file
47
tests/ui/closures/many-closures.rs
Normal 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);
|
||||
}
|
||||
24
tests/ui/coercion/basic-ptr-coercions.rs
Normal file
24
tests/ui/coercion/basic-ptr-coercions.rs
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
11
tests/ui/const-ptr/pointer-address-stability.rs
Normal file
11
tests/ui/const-ptr/pointer-address-stability.rs
Normal 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);
|
||||
}
|
||||
36
tests/ui/cross-crate/cross-crate-refcell-match.rs
Normal file
36
tests/ui/cross-crate/cross-crate-refcell-match.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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) {}
|
||||
3
tests/ui/diagnostic-flags/error-format-short.stderr
Normal file
3
tests/ui/diagnostic-flags/error-format-short.stderr
Normal 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
|
||||
|
|
@ -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() {
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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) {
|
||||
| ^^^ ------ ------ ------
|
||||
24
tests/ui/fn/mutable-function-parameters.rs
Normal file
24
tests/ui/fn/mutable-function-parameters.rs
Normal 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();
|
||||
}
|
||||
14
tests/ui/generics/generic-params-nested-fn-scope-error.rs
Normal file
14
tests/ui/generics/generic-params-nested-fn-scope-error.rs
Normal 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() {}
|
||||
|
|
@ -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>`
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
//! Test that print!/println! output to stdout and eprint!/eprintln!
|
||||
//! output to stderr correctly.
|
||||
|
||||
//@ run-pass
|
||||
//@ needs-subprocess
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
//@ run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
||||
|
||||
|
||||
mod foo {
|
||||
pub fn baz() { }
|
||||
}
|
||||
|
||||
mod bar {
|
||||
pub fn baz() { }
|
||||
}
|
||||
|
||||
pub fn main() { }
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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()) )
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
|
@ -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()));
|
||||
}
|
||||
|
|
@ -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`
|
||||
});
|
||||
}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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}`
|
||||
15
tests/ui/modules/mod-same-item-names.rs
Normal file
15
tests/ui/modules/mod-same-item-names.rs
Normal 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() {}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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() { }
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
//@ run-pass
|
||||
|
||||
/* This test checks that nested comments are supported
|
||||
|
||||
/*
|
||||
This should not panic
|
||||
*/
|
||||
*/
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
fn main() {
|
||||
|
||||
let f;
|
||||
let g;
|
||||
|
||||
g = f;
|
||||
//~^ ERROR overflow assigning `Box<_>` to `_`
|
||||
f = Box::new(g);
|
||||
}
|
||||
|
|
@ -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>(_) => { }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
fn main() {
|
||||
let f;
|
||||
f = Box::new(f);
|
||||
//~^ ERROR overflow assigning `Box<_>` to `_`
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
13
tests/ui/parser/doc-comment-in-generic.rs
Normal file
13
tests/ui/parser/doc-comment-in-generic.rs
Normal 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,
|
||||
>
|
||||
{
|
||||
}
|
||||
34
tests/ui/parser/nested-block-comments.rs
Normal file
34
tests/ui/parser/nested-block-comments.rs
Normal 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;
|
||||
}
|
||||
BIN
tests/ui/parser/raw/raw-string-literals.rs
Normal file
BIN
tests/ui/parser/raw/raw-string-literals.rs
Normal file
Binary file not shown.
|
|
@ -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`
|
||||
}
|
||||
|
|
@ -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`
|
||||
|
|
@ -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`
|
||||
}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
//@ run-pass
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(0);
|
||||
assert_eq!(0, *x + { drop(x); let _ = Box::new(main); 0 });
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
//@ compile-flags: --print calling-conventions
|
||||
//@ build-pass
|
||||
4
tests/ui/print-request/print-calling-conventions.rs
Normal file
4
tests/ui/print-request/print-calling-conventions.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//! Test that `--print calling-conventions` outputs all supported calling conventions.
|
||||
|
||||
//@ compile-flags: --print calling-conventions
|
||||
//@ build-pass
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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.
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue