Auto merge of #118780 - GuillaumeGomez:rollup-nd0syaf, r=GuillaumeGomez

Rollup of 6 pull requests

Successful merges:

 - #117953 (Add more SIMD platform-intrinsics)
 - #118057 (dedup for duplicate suggestions)
 - #118638 (More `rustc_mir_dataflow` cleanups)
 - #118702 (Strengthen well known check-cfg names and values test)
 - #118734 (Unescaping cleanups)
 - #118766 (Lower some forgotten spans)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-12-09 14:35:10 +00:00
commit 08587a56f1
35 changed files with 1115 additions and 299 deletions

View file

@ -634,7 +634,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Resume argument type: `ResumeTy`
let unstable_span = self.mark_span_with_reason(
DesugaringKind::Async,
span,
self.lower_span(span),
Some(self.allow_gen_future.clone()),
);
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);
@ -766,7 +766,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Resume argument type: `ResumeTy`
let unstable_span = self.mark_span_with_reason(
DesugaringKind::Async,
span,
self.lower_span(span),
Some(self.allow_gen_future.clone()),
);
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span);

View file

@ -1382,6 +1382,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let host_param_parts = if let Const::Yes(span) = constness
&& self.tcx.features().effects
{
let span = self.lower_span(span);
let param_node_id = self.next_node_id();
let hir_id = self.next_id();
let def_id = self.create_def(

View file

@ -1679,7 +1679,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
duplicated_lifetime_node_id,
lifetime.ident.name,
DefKind::LifetimeParam,
lifetime.ident.span,
self.lower_span(lifetime.ident.span),
);
captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
// FIXME: Instead of doing this, we could move this whole loop
@ -1688,7 +1688,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
synthesized_lifetime_definitions.push((
duplicated_lifetime_node_id,
duplicated_lifetime_def_id,
lifetime.ident,
self.lower_ident(lifetime.ident),
));
// Now make an arg that we can use for the generic params of the opaque tykind.
@ -2253,7 +2253,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match c.value.kind {
ExprKind::Underscore => {
if self.tcx.features().generic_arg_infer {
hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span))
} else {
feature_err(
&self.tcx.sess.parse_sess,

View file

@ -11,101 +11,88 @@ use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
use rustc_mir_dataflow::ResultsVisitable;
use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
use rustc_mir_dataflow::{Analysis, Direction, Results};
use rustc_mir_dataflow::{Analysis, AnalysisDomain, Results};
use std::fmt;
use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};
/// A tuple with named fields that can hold either the results or the transient state of the
/// dataflow analyses used by the borrow checker.
#[derive(Debug)]
pub struct BorrowckAnalyses<B, U, E> {
pub borrows: B,
pub uninits: U,
pub ever_inits: E,
}
/// The results of the dataflow analyses used by the borrow checker.
pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses<
Results<'tcx, Borrows<'mir, 'tcx>>,
Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
>;
pub struct BorrowckResults<'mir, 'tcx> {
pub(crate) borrows: Results<'tcx, Borrows<'mir, 'tcx>>,
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
}
/// The transient state of the dataflow analyses used by the borrow checker.
pub type BorrowckFlowState<'mir, 'tcx> =
<BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;
macro_rules! impl_visitable {
( $(
$T:ident { $( $field:ident : $A:ident ),* $(,)? }
)* ) => { $(
impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*>
where
$( $A: Analysis<'tcx, Direction = D>, )*
{
type Direction = D;
type FlowState = $T<$( $A::Domain ),*>;
fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
$T {
$( $field: self.$field.analysis.bottom_value(body) ),*
}
}
fn reset_to_block_entry(
&self,
state: &mut Self::FlowState,
block: BasicBlock,
) {
$( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )*
}
fn reconstruct_before_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_before_statement_effect(&mut state.$field, stmt, loc); )*
}
fn reconstruct_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_statement_effect(&mut state.$field, stmt, loc); )*
}
fn reconstruct_before_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_before_terminator_effect(&mut state.$field, term, loc); )*
}
fn reconstruct_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
$( self.$field.analysis
.apply_terminator_effect(&mut state.$field, term, loc); )*
}
}
)* }
#[derive(Debug)]
pub struct BorrowckFlowState<'mir, 'tcx> {
pub(crate) borrows: <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) uninits: <MaybeUninitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
pub(crate) ever_inits: <EverInitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain,
}
impl_visitable! {
BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> {
// All three analyses are forward, but we have to use just one here.
type Direction = <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction;
type FlowState = BorrowckFlowState<'mir, 'tcx>;
fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
BorrowckFlowState {
borrows: self.borrows.analysis.bottom_value(body),
uninits: self.uninits.analysis.bottom_value(body),
ever_inits: self.ever_inits.analysis.bottom_value(body),
}
}
fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
state.borrows.clone_from(&self.borrows.entry_set_for_block(block));
state.uninits.clone_from(&self.uninits.entry_set_for_block(block));
state.ever_inits.clone_from(&self.ever_inits.entry_set_for_block(block));
}
fn reconstruct_before_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
}
fn reconstruct_statement_effect(
&mut self,
state: &mut Self::FlowState,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
}
fn reconstruct_before_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
}
fn reconstruct_terminator_effect(
&mut self,
state: &mut Self::FlowState,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
}
}
rustc_index::newtype_index! {
@ -598,7 +585,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
fn before_terminator_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
) {
@ -625,7 +612,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
fn call_return_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {

View file

@ -1,5 +1,6 @@
//! Codegen `extern "platform-intrinsic"` intrinsics.
use cranelift_codegen::ir::immediates::Offset32;
use rustc_middle::ty::GenericArgsRef;
use rustc_span::Symbol;
use rustc_target::abi::Endian;
@ -1008,8 +1009,57 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
}
}
sym::simd_masked_load => {
intrinsic_args!(fx, args => (mask, ptr, val); intrinsic);
let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(val_lane_count, mask_lane_count);
assert_eq!(val_lane_count, ret_lane_count);
let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
let ret_lane_layout = fx.layout_of(ret_lane_ty);
let ptr_val = ptr.load_scalar(fx);
for lane_idx in 0..ret_lane_count {
let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
let if_enabled = fx.bcx.create_block();
let if_disabled = fx.bcx.create_block();
let next = fx.bcx.create_block();
let res_lane = fx.bcx.append_block_param(next, lane_clif_ty);
fx.bcx.ins().brif(mask_lane, if_enabled, &[], if_disabled, &[]);
fx.bcx.seal_block(if_enabled);
fx.bcx.seal_block(if_disabled);
fx.bcx.switch_to_block(if_enabled);
let offset = lane_idx as i32 * lane_clif_ty.bytes() as i32;
let res = fx.bcx.ins().load(
lane_clif_ty,
MemFlags::trusted(),
ptr_val,
Offset32::new(offset),
);
fx.bcx.ins().jump(next, &[res]);
fx.bcx.switch_to_block(if_disabled);
fx.bcx.ins().jump(next, &[val_lane]);
fx.bcx.seal_block(next);
fx.bcx.switch_to_block(next);
fx.bcx.ins().nop();
ret.place_lane(fx, lane_idx)
.write_cvalue(fx, CValue::by_val(res_lane, ret_lane_layout));
}
}
sym::simd_scatter => {
intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
intrinsic_args!(fx, args => (mask, ptr, val); intrinsic);
let (val_lane_count, _val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);

View file

@ -1492,6 +1492,198 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
return Ok(v);
}
if name == sym::simd_masked_load {
// simd_masked_load(mask: <N x i{M}>, pointer: *_ T, values: <N x T>) -> <N x T>
// * N: number of elements in the input vectors
// * T: type of the element to load
// * M: any integer width is supported, will be truncated to i1
// Loads contiguous elements from memory behind `pointer`, but only for
// those lanes whose `mask` bit is enabled.
// The memory addresses corresponding to the “off” lanes are not accessed.
// The element type of the "mask" argument must be a signed integer type of any width
let mask_ty = in_ty;
let (mask_len, mask_elem) = (in_len, in_elem);
// The second argument must be a pointer matching the element type
let pointer_ty = arg_tys[1];
// The last argument is a passthrough vector providing values for disabled lanes
let values_ty = arg_tys[2];
let (values_len, values_elem) = require_simd!(values_ty, SimdThird);
require_simd!(ret_ty, SimdReturn);
// Of the same length:
require!(
values_len == mask_len,
InvalidMonomorphization::ThirdArgumentLength {
span,
name,
in_len: mask_len,
in_ty: mask_ty,
arg_ty: values_ty,
out_len: values_len
}
);
// The return type must match the last argument type
require!(
ret_ty == values_ty,
InvalidMonomorphization::ExpectedReturnType { span, name, in_ty: values_ty, ret_ty }
);
require!(
matches!(
pointer_ty.kind(),
ty::RawPtr(p) if p.ty == values_elem && p.ty.kind() == values_elem.kind()
),
InvalidMonomorphization::ExpectedElementType {
span,
name,
expected_element: values_elem,
second_arg: pointer_ty,
in_elem: values_elem,
in_ty: values_ty,
mutability: ExpectedPointerMutability::Not,
}
);
require!(
matches!(mask_elem.kind(), ty::Int(_)),
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: values_elem,
third_arg: mask_ty,
}
);
// Alignment of T, must be a constant integer value:
let alignment_ty = bx.type_i32();
let alignment = bx.const_i32(bx.align_of(values_ty).bytes() as i32);
// Truncate the mask vector to a vector of i1s:
let (mask, mask_ty) = {
let i1 = bx.type_i1();
let i1xn = bx.type_vector(i1, mask_len);
(bx.trunc(args[0].immediate(), i1xn), i1xn)
};
let llvm_pointer = bx.type_ptr();
// Type of the vector of elements:
let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len);
let llvm_intrinsic = format!("llvm.masked.load.{llvm_elem_vec_str}.p0");
let fn_ty = bx
.type_func(&[llvm_pointer, alignment_ty, mask_ty, llvm_elem_vec_ty], llvm_elem_vec_ty);
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
let v = bx.call(
fn_ty,
None,
None,
f,
&[args[1].immediate(), alignment, mask, args[2].immediate()],
None,
);
return Ok(v);
}
if name == sym::simd_masked_store {
// simd_masked_store(mask: <N x i{M}>, pointer: *mut T, values: <N x T>) -> ()
// * N: number of elements in the input vectors
// * T: type of the element to load
// * M: any integer width is supported, will be truncated to i1
// Stores contiguous elements to memory behind `pointer`, but only for
// those lanes whose `mask` bit is enabled.
// The memory addresses corresponding to the “off” lanes are not accessed.
// The element type of the "mask" argument must be a signed integer type of any width
let mask_ty = in_ty;
let (mask_len, mask_elem) = (in_len, in_elem);
// The second argument must be a pointer matching the element type
let pointer_ty = arg_tys[1];
// The last argument specifies the values to store to memory
let values_ty = arg_tys[2];
let (values_len, values_elem) = require_simd!(values_ty, SimdThird);
// Of the same length:
require!(
values_len == mask_len,
InvalidMonomorphization::ThirdArgumentLength {
span,
name,
in_len: mask_len,
in_ty: mask_ty,
arg_ty: values_ty,
out_len: values_len
}
);
// The second argument must be a mutable pointer type matching the element type
require!(
matches!(
pointer_ty.kind(),
ty::RawPtr(p) if p.ty == values_elem && p.ty.kind() == values_elem.kind() && p.mutbl.is_mut()
),
InvalidMonomorphization::ExpectedElementType {
span,
name,
expected_element: values_elem,
second_arg: pointer_ty,
in_elem: values_elem,
in_ty: values_ty,
mutability: ExpectedPointerMutability::Mut,
}
);
require!(
matches!(mask_elem.kind(), ty::Int(_)),
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: values_elem,
third_arg: mask_ty,
}
);
// Alignment of T, must be a constant integer value:
let alignment_ty = bx.type_i32();
let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32);
// Truncate the mask vector to a vector of i1s:
let (mask, mask_ty) = {
let i1 = bx.type_i1();
let i1xn = bx.type_vector(i1, in_len);
(bx.trunc(args[0].immediate(), i1xn), i1xn)
};
let ret_t = bx.type_void();
let llvm_pointer = bx.type_ptr();
// Type of the vector of elements:
let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len);
let llvm_intrinsic = format!("llvm.masked.store.{llvm_elem_vec_str}.p0");
let fn_ty = bx.type_func(&[llvm_elem_vec_ty, llvm_pointer, alignment_ty, mask_ty], ret_t);
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
let v = bx.call(
fn_ty,
None,
None,
f,
&[args[2].immediate(), args[1].immediate(), alignment, mask],
None,
);
return Ok(v);
}
if name == sym::simd_scatter {
// simd_scatter(values: <N x T>, pointers: <N x *mut T>,
// mask: <N x i{M}>) -> ()

View file

@ -591,17 +591,18 @@ impl Diagnostic {
pub fn multipart_suggestion_with_style(
&mut self,
msg: impl Into<SubdiagnosticMessage>,
suggestion: Vec<(Span, String)>,
mut suggestion: Vec<(Span, String)>,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
let mut parts = suggestion
suggestion.sort_unstable();
suggestion.dedup();
let parts = suggestion
.into_iter()
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect::<Vec<_>>();
parts.sort_unstable_by_key(|part| part.span);
assert!(!parts.is_empty());
debug_assert_eq!(
parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),

View file

@ -521,6 +521,8 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)),
sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)),
sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)),
sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)),
sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)),
sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)),
sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)),
sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)),

View file

@ -4,10 +4,14 @@
use std::ops::Range;
use std::str::Chars;
use Mode::*;
#[cfg(test)]
mod tests;
/// Errors and warnings that can occur during string unescaping.
/// Errors and warnings that can occur during string unescaping. They mostly
/// relate to malformed escape sequences, but there are a few that are about
/// other problems.
#[derive(Debug, PartialEq, Eq)]
pub enum EscapeError {
/// Expected 1 char, but 0 were found.
@ -73,25 +77,24 @@ impl EscapeError {
}
}
/// Takes a contents of a literal (without quotes) and produces a
/// sequence of escaped characters or errors.
/// Values are returned through invoking of the provided callback.
/// Takes a contents of a literal (without quotes) and produces a sequence of
/// escaped characters or errors.
///
/// Values are returned by invoking `callback`. For `Char` and `Byte` modes,
/// the callback will be called exactly once.
pub fn unescape_literal<F>(src: &str, mode: Mode, callback: &mut F)
where
F: FnMut(Range<usize>, Result<char, EscapeError>),
{
match mode {
Mode::Char | Mode::Byte => {
Char | Byte => {
let mut chars = src.chars();
let res = unescape_char_or_byte(&mut chars, mode == Mode::Byte);
let res = unescape_char_or_byte(&mut chars, mode);
callback(0..(src.len() - chars.as_str().len()), res);
}
Mode::Str | Mode::ByteStr => unescape_str_common(src, mode, callback),
Mode::RawStr | Mode::RawByteStr => {
unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
}
Mode::CStr | Mode::RawCStr => unreachable!(),
Str | ByteStr => unescape_str_common(src, mode, callback),
RawStr | RawByteStr => unescape_raw_str_or_raw_byte_str(src, mode, callback),
CStr | RawCStr => unreachable!(),
}
}
@ -117,38 +120,44 @@ pub fn unescape_c_string<F>(src: &str, mode: Mode, callback: &mut F)
where
F: FnMut(Range<usize>, Result<CStrUnit, EscapeError>),
{
if mode == Mode::RawCStr {
unescape_raw_str_or_raw_byte_str(
src,
mode.characters_should_be_ascii(),
&mut |r, result| callback(r, result.map(CStrUnit::Char)),
);
} else {
unescape_str_common(src, mode, callback);
match mode {
CStr => {
unescape_str_common(src, mode, callback);
}
RawCStr => {
unescape_raw_str_or_raw_byte_str(src, mode, &mut |r, result| {
callback(r, result.map(CStrUnit::Char))
});
}
Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(),
}
}
/// Takes a contents of a char literal (without quotes), and returns an
/// unescaped char or an error.
pub fn unescape_char(src: &str) -> Result<char, EscapeError> {
unescape_char_or_byte(&mut src.chars(), false)
unescape_char_or_byte(&mut src.chars(), Char)
}
/// Takes a contents of a byte literal (without quotes), and returns an
/// unescaped byte or an error.
pub fn unescape_byte(src: &str) -> Result<u8, EscapeError> {
unescape_char_or_byte(&mut src.chars(), true).map(byte_from_char)
unescape_char_or_byte(&mut src.chars(), Byte).map(byte_from_char)
}
/// What kind of literal do we parse.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Mode {
Char,
Str,
Byte,
ByteStr,
Str,
RawStr,
ByteStr,
RawByteStr,
CStr,
RawCStr,
}
@ -156,45 +165,42 @@ pub enum Mode {
impl Mode {
pub fn in_double_quotes(self) -> bool {
match self {
Mode::Str
| Mode::ByteStr
| Mode::RawStr
| Mode::RawByteStr
| Mode::CStr
| Mode::RawCStr => true,
Mode::Char | Mode::Byte => false,
Str | RawStr | ByteStr | RawByteStr | CStr | RawCStr => true,
Char | Byte => false,
}
}
/// Non-byte literals should have `\xXX` escapes that are within the ASCII range.
pub fn ascii_escapes_should_be_ascii(self) -> bool {
fn ascii_escapes_should_be_ascii(self) -> bool {
match self {
Mode::Char | Mode::Str | Mode::RawStr => true,
Mode::Byte | Mode::ByteStr | Mode::RawByteStr | Mode::CStr | Mode::RawCStr => false,
Char | Str => true,
Byte | ByteStr | CStr => false,
RawStr | RawByteStr | RawCStr => unreachable!(),
}
}
/// Whether characters within the literal must be within the ASCII range
pub fn characters_should_be_ascii(self) -> bool {
/// Whether characters within the literal must be within the ASCII range.
#[inline]
fn chars_should_be_ascii(self) -> bool {
match self {
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
Byte | ByteStr | RawByteStr => true,
Char | Str | RawStr | CStr | RawCStr => false,
}
}
/// Byte literals do not allow unicode escape.
pub fn is_unicode_escape_disallowed(self) -> bool {
fn is_unicode_escape_disallowed(self) -> bool {
match self {
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
Byte | ByteStr | RawByteStr => true,
Char | Str | RawStr | CStr | RawCStr => false,
}
}
pub fn prefix_noraw(self) -> &'static str {
match self {
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => "b",
Mode::CStr | Mode::RawCStr => "c",
Mode::Char | Mode::Str | Mode::RawStr => "",
Char | Str | RawStr => "",
Byte | ByteStr | RawByteStr => "b",
CStr | RawCStr => "c",
}
}
}
@ -294,22 +300,21 @@ fn scan_unicode(
}
#[inline]
fn ascii_check(c: char, characters_should_be_ascii: bool) -> Result<char, EscapeError> {
if characters_should_be_ascii && !c.is_ascii() {
// Byte literal can't be a non-ascii character.
fn ascii_check(c: char, chars_should_be_ascii: bool) -> Result<char, EscapeError> {
if chars_should_be_ascii && !c.is_ascii() {
Err(EscapeError::NonAsciiCharInByte)
} else {
Ok(c)
}
}
fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
let c = chars.next().ok_or(EscapeError::ZeroChars)?;
let res = match c {
'\\' => scan_escape(chars, if is_byte { Mode::Byte } else { Mode::Char }),
'\\' => scan_escape(chars, mode),
'\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
'\r' => Err(EscapeError::BareCarriageReturn),
_ => ascii_check(c, is_byte),
_ => ascii_check(c, mode.chars_should_be_ascii()),
}?;
if chars.next().is_some() {
return Err(EscapeError::MoreThanOneChar);
@ -324,6 +329,7 @@ where
F: FnMut(Range<usize>, Result<T, EscapeError>),
{
let mut chars = src.chars();
let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop
// The `start` and `end` computation here is complicated because
// `skip_ascii_whitespace` makes us to skip over chars without counting
@ -346,14 +352,12 @@ where
_ => scan_escape::<T>(&mut chars, mode),
}
}
'\n' => Ok(b'\n'.into()),
'\t' => Ok(b'\t'.into()),
'"' => Err(EscapeError::EscapeOnlyChar),
'\r' => Err(EscapeError::BareCarriageReturn),
_ => ascii_check(c, mode.characters_should_be_ascii()).map(Into::into),
_ => ascii_check(c, chars_should_be_ascii).map(Into::into),
};
let end = src.len() - chars.as_str().len();
callback(start..end, res.map(Into::into));
callback(start..end, res);
}
}
@ -387,20 +391,21 @@ where
/// sequence of characters or errors.
/// NOTE: Raw strings do not perform any explicit character escaping, here we
/// only produce errors on bare CR.
fn unescape_raw_str_or_raw_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
fn unescape_raw_str_or_raw_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
where
F: FnMut(Range<usize>, Result<char, EscapeError>),
{
let mut chars = src.chars();
let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop
// The `start` and `end` computation here matches the one in
// `unescape_str_or_byte_str` for consistency, even though this function
// `unescape_str_common` for consistency, even though this function
// doesn't have to worry about skipping any chars.
while let Some(c) = chars.next() {
let start = src.len() - chars.as_str().len() - c.len_utf8();
let res = match c {
'\r' => Err(EscapeError::BareCarriageReturnInRawString),
_ => ascii_check(c, is_byte),
_ => ascii_check(c, chars_should_be_ascii),
};
let end = src.len() - chars.as_str().len();
callback(start..end, res);
@ -410,7 +415,7 @@ where
#[inline]
pub fn byte_from_char(c: char) -> u8 {
let res = c as u32;
debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
debug_assert!(res <= u8::MAX as u32, "guaranteed because of ByteStr");
res as u8
}

View file

@ -196,7 +196,7 @@ impl Direction for Backward {
{
results.reset_to_block_entry(state, block);
vis.visit_block_end(results, state, block_data, block);
vis.visit_block_end(state);
// Terminator
let loc = Location { block, statement_index: block_data.statements.len() };
@ -214,7 +214,7 @@ impl Direction for Backward {
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
}
vis.visit_block_start(results, state, block_data, block);
vis.visit_block_start(state);
}
fn join_state_into_successors_of<'tcx, A>(
@ -449,7 +449,7 @@ impl Direction for Forward {
{
results.reset_to_block_entry(state, block);
vis.visit_block_start(results, state, block_data, block);
vis.visit_block_start(state);
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
let loc = Location { block, statement_index };
@ -466,7 +466,7 @@ impl Direction for Forward {
results.reconstruct_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc);
vis.visit_block_end(results, state, block_data, block);
vis.visit_block_end(state);
}
fn join_state_into_successors_of<'tcx, A>(

View file

@ -545,25 +545,13 @@ where
{
type FlowState = A::Domain;
fn visit_block_start(
&mut self,
_results: &mut Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
fn visit_block_start(&mut self, state: &Self::FlowState) {
if A::Direction::IS_FORWARD {
self.prev_state.clone_from(state);
}
}
fn visit_block_end(
&mut self,
_results: &mut Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
fn visit_block_end(&mut self, state: &Self::FlowState) {
if A::Direction::IS_BACKWARD {
self.prev_state.clone_from(state);
}

View file

@ -248,18 +248,19 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// A gen/kill dataflow problem.
///
/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
/// allow modification of the dataflow state via "gen" and "kill" operations. By defining transfer
/// functions for each statement in this way, the transfer function for an entire basic block can
/// be computed efficiently.
/// Each method in this trait has a corresponding one in `Analysis`. However, the first two methods
/// here only allow modification of the dataflow state via "gen" and "kill" operations. By defining
/// transfer functions for each statement in this way, the transfer function for an entire basic
/// block can be computed efficiently. The remaining methods match up with `Analysis` exactly.
///
/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`.
/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis` via a blanket
/// impl below.
pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
type Idx: Idx;
fn domain_size(&self, body: &mir::Body<'tcx>) -> usize;
/// See `Analysis::apply_statement_effect`.
/// See `Analysis::apply_statement_effect`. Note how the second arg differs.
fn statement_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
@ -267,7 +268,8 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
location: Location,
);
/// See `Analysis::apply_before_statement_effect`.
/// See `Analysis::apply_before_statement_effect`. Note how the second arg
/// differs.
fn before_statement_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
@ -287,7 +289,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_before_terminator_effect`.
fn before_terminator_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
@ -298,7 +300,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
/// See `Analysis::apply_call_return_effect`.
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
);
@ -313,6 +315,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
}
}
// Blanket impl: any impl of `GenKillAnalysis` automatically impls `Analysis`.
impl<'tcx, A> Analysis<'tcx> for A
where
A: GenKillAnalysis<'tcx>,

View file

@ -31,14 +31,7 @@ pub fn visit_results<'mir, 'tcx, F, R>(
pub trait ResultsVisitor<'mir, 'tcx, R> {
type FlowState;
fn visit_block_start(
&mut self,
_results: &mut R,
_state: &Self::FlowState,
_block_data: &'mir mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
}
fn visit_block_start(&mut self, _state: &Self::FlowState) {}
/// Called with the `before_statement_effect` of the given statement applied to `state` but not
/// its `statement_effect`.
@ -86,20 +79,13 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
) {
}
fn visit_block_end(
&mut self,
_results: &mut R,
_state: &Self::FlowState,
_block_data: &'mir mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
}
fn visit_block_end(&mut self, _state: &Self::FlowState) {}
}
/// Things that can be visited by a `ResultsVisitor`.
///
/// This trait exists so that we can visit the results of multiple dataflow analyses simultaneously.
/// DO NOT IMPLEMENT MANUALLY. Instead, use the `impl_visitable` macro below.
/// This trait exists so that we can visit the results of one or more dataflow analyses
/// simultaneously.
pub trait ResultsVisitable<'tcx> {
type Direction: Direction;
type FlowState;

View file

@ -62,7 +62,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
fn call_return_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {

View file

@ -376,7 +376,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -499,7 +499,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -617,7 +617,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -712,7 +712,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {

View file

@ -69,7 +69,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {

View file

@ -72,7 +72,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
fn call_return_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -144,7 +144,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
fn call_return_effect(
&mut self,
_trans: &mut impl GenKill<Self::Idx>,
_trans: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -238,7 +238,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
fn before_terminator_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
terminator: &Terminator<'tcx>,
loc: Location,
) {
@ -334,7 +334,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
fn call_return_effect(
&mut self,
trans: &mut impl GenKill<Self::Idx>,
trans: &mut Self::Domain,
_block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {

View file

@ -1422,6 +1422,9 @@ impl CheckCfg {
};
// NOTE: This should be kept in sync with `default_configuration`
//
// When adding a new config here you should also update
// `tests/ui/check-cfg/well-known-values.rs`.
let panic_values = &PanicStrategy::all();

View file

@ -1516,6 +1516,8 @@ symbols! {
simd_insert,
simd_le,
simd_lt,
simd_masked_load,
simd_masked_store,
simd_mul,
simd_ne,
simd_neg,

View file

@ -0,0 +1,34 @@
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
#![feature(repr_simd, platform_intrinsics)]
#![allow(non_camel_case_types)]
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Vec2<T>(pub T, pub T);
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Vec4<T>(pub T, pub T, pub T, pub T);
extern "platform-intrinsic" {
fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
}
// CHECK-LABEL: @load_f32x2
#[no_mangle]
pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32,
values: Vec2<f32>) -> Vec2<f32> {
// CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 {{.*}}, <2 x i1> {{.*}}, <2 x float> {{.*}})
simd_masked_load(mask, pointer, values)
}
// CHECK-LABEL: @load_pf32x4
#[no_mangle]
pub unsafe fn load_pf32x4(mask: Vec4<i32>, pointer: *const *const f32,
values: Vec4<*const f32>) -> Vec4<*const f32> {
// CHECK: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr {{.*}}, i32 {{.*}}, <4 x i1> {{.*}}, <4 x ptr> {{.*}})
simd_masked_load(mask, pointer, values)
}

View file

@ -0,0 +1,32 @@
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
#![feature(repr_simd, platform_intrinsics)]
#![allow(non_camel_case_types)]
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Vec2<T>(pub T, pub T);
#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Vec4<T>(pub T, pub T, pub T, pub T);
extern "platform-intrinsic" {
fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T) -> ();
}
// CHECK-LABEL: @store_f32x2
#[no_mangle]
pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>) {
// CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 {{.*}}, <2 x i1> {{.*}})
simd_masked_store(mask, pointer, values)
}
// CHECK-LABEL: @store_pf32x4
#[no_mangle]
pub unsafe fn store_pf32x4(mask: Vec4<i32>, pointer: *mut *const f32, values: Vec4<*const f32>) {
// CHECK: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr {{.*}}, i32 {{.*}}, <4 x i1> {{.*}})
simd_masked_store(mask, pointer, values)
}

View file

@ -8,7 +8,7 @@
#[cfg(target(os = "linux", arch = "arm"))]
pub fn expected() {}
#[cfg(target(os = "linux", arch = "X"))]
#[cfg(target(os = "linux", pointer_width = "X"))]
//~^ WARNING unexpected `cfg` condition value
pub fn unexpected() {}

View file

@ -1,10 +1,10 @@
warning: unexpected `cfg` condition value: `X`
--> $DIR/compact-values.rs:11:28
|
LL | #[cfg(target(os = "linux", arch = "X"))]
| ^^^^^^^^^^
LL | #[cfg(target(os = "linux", pointer_width = "X"))]
| ^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_arch` are: `aarch64`, `arm`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`
= note: expected values for `target_pointer_width` are: `16`, `32`, `64`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: 1 warning emitted

View file

@ -10,10 +10,6 @@
#[lang = "sized"]
trait Sized {}
#[cfg(target_os = "linuz")]
//~^ WARNING unexpected `cfg` condition value
fn target_os_linux_misspell() {}
#[cfg(target_os = "linux")]
fn target_os_linux() {}

View file

@ -1,13 +0,0 @@
warning: unexpected `cfg` condition value: `linuz`
--> $DIR/values-target-json.rs:13:7
|
LL | #[cfg(target_os = "linuz")]
| ^^^^^^^^^^^^-------
| |
| help: there is a expected value with a similar name: `"linux"`
|
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: 1 warning emitted

View file

@ -1,41 +1,104 @@
// This test check that we lint on non well known values and that we don't lint on well known
// values
// This test check that we recognize all the well known config names
// and that we correctly lint on unexpected values.
//
// This test also serve as an "anti-regression" for the well known
// values since the suggestion shows them.
//
// check-pass
// compile-flags: --check-cfg=cfg() -Z unstable-options
#[cfg(target_os = "linuz")]
#![feature(cfg_overflow_checks)]
#![feature(cfg_relocation_model)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_abi)]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_has_atomic_equal_alignment)]
#![feature(cfg_target_thread_local)]
// This part makes sure that none of the well known names are
// unexpected.
//
// BUT to make sure that no expected values changes without
// being noticed we pass them a obviously wrong value so the
// diagnostic prints the list of expected values.
#[cfg(any(
// tidy-alphabetical-start
debug_assertions = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
doc = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
doctest = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
miri = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
overflow_checks = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
panic = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
proc_macro = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
relocation_model = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
sanitize = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_abi = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_arch = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_endian = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_env = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_family = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_feature = "_UNEXPECTED_VALUE", // currently *any* values are "expected"
target_has_atomic = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_has_atomic_load_store = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_os = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_pointer_width = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_thread_local = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
target_vendor = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
test = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
unix = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
windows = "_UNEXPECTED_VALUE",
//~^ WARN unexpected `cfg` condition value
// tidy-alphabetical-end
))]
fn unexpected_values() {}
#[cfg(target_os = "linuz")] // testing that we suggest `linux`
//~^ WARNING unexpected `cfg` condition value
fn target_os_linux_misspell() {}
// The #[cfg]s below serve as a safeguard to make sure we
// don't lint when using an expected well-known name and
// value, only a small subset of all possible expected
// configs are tested, since we already test the names
// above and don't need to test all values, just different
// combinations (without value, with value, both...).
#[cfg(target_os = "linux")]
fn target_os_linux() {}
#[cfg(target_has_atomic = "0")]
//~^ WARNING unexpected `cfg` condition value
fn target_has_atomic_invalid() {}
#[cfg(target_has_atomic = "8")]
fn target_has_atomic() {}
fn target_has_atomic_8() {}
#[cfg(unix = "aa")]
//~^ WARNING unexpected `cfg` condition value
fn unix_with_value() {}
#[cfg(target_has_atomic)]
fn target_has_atomic() {}
#[cfg(unix)]
fn unix() {}
#[cfg(miri = "miri")]
//~^ WARNING unexpected `cfg` condition value
fn miri_with_value() {}
#[cfg(miri)]
fn miri() {}
#[cfg(doc = "linux")]
//~^ WARNING unexpected `cfg` condition value
fn doc_with_value() {}
#[cfg(doc)]
fn doc() {}

View file

@ -1,53 +1,225 @@
warning: unexpected `cfg` condition value: `linuz`
--> $DIR/well-known-values.rs:7:7
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:26:5
|
LL | #[cfg(target_os = "linuz")]
LL | debug_assertions = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `debug_assertions`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:28:5
|
LL | doc = "_UNEXPECTED_VALUE",
| ^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `doc`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:30:5
|
LL | doctest = "_UNEXPECTED_VALUE",
| ^^^^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `doctest`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:32:5
|
LL | miri = "_UNEXPECTED_VALUE",
| ^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `miri`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:34:5
|
LL | overflow_checks = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `overflow_checks`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:36:5
|
LL | panic = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `panic` are: `abort`, `unwind`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:38:5
|
LL | proc_macro = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `proc_macro`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:40:5
|
LL | relocation_model = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `relocation_model` are: `dynamic-no-pic`, `pic`, `pie`, `ropi`, `ropi-rwpi`, `rwpi`, `static`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:42:5
|
LL | sanitize = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `sanitize` are: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:44:5
|
LL | target_abi = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, `x32`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:46:5
|
LL | target_arch = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_arch` are: `aarch64`, `arm`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:48:5
|
LL | target_endian = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_endian` are: `big`, `little`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:50:5
|
LL | target_env = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_env` are: ``, `eabihf`, `gnu`, `gnueabihf`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `psx`, `relibc`, `sgx`, `uclibc`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:52:5
|
LL | target_family = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_family` are: `unix`, `wasm`, `windows`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:55:5
|
LL | target_has_atomic = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:57:5
|
LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_has_atomic_equal_alignment` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:59:5
|
LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_has_atomic_load_store` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:61:5
|
LL | target_os = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:63:5
|
LL | target_pointer_width = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_pointer_width` are: `16`, `32`, `64`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:65:5
|
LL | target_thread_local = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `target_thread_local`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:67:5
|
LL | target_vendor = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, `wrs`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:69:5
|
LL | test = "_UNEXPECTED_VALUE",
| ^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `test`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:71:5
|
LL | unix = "_UNEXPECTED_VALUE",
| ^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `unix`
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
--> $DIR/well-known-values.rs:73:5
|
LL | windows = "_UNEXPECTED_VALUE",
| ^^^^^^^----------------------
| |
| help: remove the value
|
= note: no expected value for `windows`
warning: unexpected `cfg` condition value: `linuz`
--> $DIR/well-known-values.rs:79:7
|
LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
| ^^^^^^^^^^^^-------
| |
| help: there is a expected value with a similar name: `"linux"`
|
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value: `0`
--> $DIR/well-known-values.rs:14:7
|
LL | #[cfg(target_has_atomic = "0")]
| ^^^^^^^^^^^^^^^^^^^^---
| |
| help: there is a expected value with a similar name: `"8"`
|
= note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
warning: unexpected `cfg` condition value: `aa`
--> $DIR/well-known-values.rs:21:7
|
LL | #[cfg(unix = "aa")]
| ^^^^-------
| |
| help: remove the value
|
= note: no expected value for `unix`
warning: unexpected `cfg` condition value: `miri`
--> $DIR/well-known-values.rs:28:7
|
LL | #[cfg(miri = "miri")]
| ^^^^---------
| |
| help: remove the value
|
= note: no expected value for `miri`
warning: unexpected `cfg` condition value: `linux`
--> $DIR/well-known-values.rs:35:7
|
LL | #[cfg(doc = "linux")]
| ^^^----------
| |
| help: remove the value
|
= note: no expected value for `doc`
warning: 5 warnings emitted
warning: 25 warnings emitted

View file

@ -0,0 +1,10 @@
macro_rules! foo {
($ty:ty) => {
fn foo(_: $ty, _: $ty) {}
}
}
foo!(_);
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
fn main() {}

View file

@ -0,0 +1,21 @@
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/issue-118048.rs:7:6
|
LL | foo!(_);
| ^
| |
| not allowed in type signatures
| not allowed in type signatures
|
help: use type parameters instead
|
LL ~ fn foo<T>(_: $ty, _: $ty) {}
LL | }
LL | }
LL |
LL ~ foo!(T);
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0121`.

View file

@ -0,0 +1,74 @@
// build-fail
#![feature(repr_simd, platform_intrinsics)]
extern "platform-intrinsic" {
fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T) -> ();
}
#[derive(Copy, Clone)]
#[repr(simd)]
struct Simd<T, const N: usize>([T; N]);
fn main() {
unsafe {
let mut arr = [4u8, 5, 6, 7];
let default = Simd::<u8, 4>([9; 4]);
simd_masked_load(
Simd::<i8, 8>([-1, 0, -1, -1, 0, 0, 0, 0]),
arr.as_ptr(),
default
);
//~^^^^^ ERROR expected third argument with length 8 (same as input type `Simd<i8, 8>`), found `Simd<u8, 4>` with length 4
simd_masked_load(
Simd::<i8, 4>([-1, 0, -1, -1]),
arr.as_ptr() as *const i8,
default
);
//~^^^^^ ERROR expected element type `u8` of second argument `*const i8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*_ u8`
simd_masked_load(
Simd::<i8, 4>([-1, 0, -1, -1]),
arr.as_ptr(),
Simd::<u32, 4>([9; 4])
);
//~^^^^^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*_ u32`
simd_masked_load(
Simd::<u8, 4>([1, 0, 1, 1]),
arr.as_ptr(),
default
);
//~^^^^^ ERROR expected element type `u8` of third argument `Simd<u8, 4>` to be a signed integer type
simd_masked_store(
Simd([-1i8; 4]),
arr.as_ptr(),
Simd([5u32; 4])
);
//~^^^^^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
simd_masked_store(
Simd([-1i8; 4]),
arr.as_ptr(),
Simd([5u8; 4])
);
//~^^^^^ ERROR expected element type `u8` of second argument `*const u8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*mut u8`
simd_masked_store(
Simd([-1i8; 4]),
arr.as_mut_ptr(),
Simd([5u8; 2])
);
//~^^^^^ ERROR expected third argument with length 4 (same as input type `Simd<i8, 4>`), found `Simd<u8, 2>` with length 2
simd_masked_store(
Simd([1u32; 4]),
arr.as_mut_ptr(),
Simd([5u8; 4])
);
//~^^^^^ ERROR expected element type `u8` of third argument `Simd<u32, 4>` to be a signed integer type
}
}

View file

@ -0,0 +1,83 @@
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected third argument with length 8 (same as input type `Simd<i8, 8>`), found `Simd<u8, 4>` with length 4
--> $DIR/masked-load-store-build-fail.rs:18:9
|
LL | / simd_masked_load(
LL | | Simd::<i8, 8>([-1, 0, -1, -1, 0, 0, 0, 0]),
LL | | arr.as_ptr(),
LL | | default
LL | | );
| |_________^
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u8` of second argument `*const i8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*_ u8`
--> $DIR/masked-load-store-build-fail.rs:25:9
|
LL | / simd_masked_load(
LL | | Simd::<i8, 4>([-1, 0, -1, -1]),
LL | | arr.as_ptr() as *const i8,
LL | | default
LL | | );
| |_________^
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*_ u32`
--> $DIR/masked-load-store-build-fail.rs:32:9
|
LL | / simd_masked_load(
LL | | Simd::<i8, 4>([-1, 0, -1, -1]),
LL | | arr.as_ptr(),
LL | | Simd::<u32, 4>([9; 4])
LL | | );
| |_________^
error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u8` of third argument `Simd<u8, 4>` to be a signed integer type
--> $DIR/masked-load-store-build-fail.rs:39:9
|
LL | / simd_masked_load(
LL | | Simd::<u8, 4>([1, 0, 1, 1]),
LL | | arr.as_ptr(),
LL | | default
LL | | );
| |_________^
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
--> $DIR/masked-load-store-build-fail.rs:46:9
|
LL | / simd_masked_store(
LL | | Simd([-1i8; 4]),
LL | | arr.as_ptr(),
LL | | Simd([5u32; 4])
LL | | );
| |_________^
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u8` of second argument `*const u8` to be a pointer to the element type `u8` of the first argument `Simd<u8, 4>`, found `u8` != `*mut u8`
--> $DIR/masked-load-store-build-fail.rs:53:9
|
LL | / simd_masked_store(
LL | | Simd([-1i8; 4]),
LL | | arr.as_ptr(),
LL | | Simd([5u8; 4])
LL | | );
| |_________^
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected third argument with length 4 (same as input type `Simd<i8, 4>`), found `Simd<u8, 2>` with length 2
--> $DIR/masked-load-store-build-fail.rs:60:9
|
LL | / simd_masked_store(
LL | | Simd([-1i8; 4]),
LL | | arr.as_mut_ptr(),
LL | | Simd([5u8; 2])
LL | | );
| |_________^
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u8` of third argument `Simd<u32, 4>` to be a signed integer type
--> $DIR/masked-load-store-build-fail.rs:67:9
|
LL | / simd_masked_store(
LL | | Simd([1u32; 4]),
LL | | arr.as_mut_ptr(),
LL | | Simd([5u8; 4])
LL | | );
| |_________^
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0511`.

View file

@ -0,0 +1,32 @@
// check-fail
#![feature(repr_simd, platform_intrinsics)]
extern "platform-intrinsic" {
fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T) -> ();
}
#[derive(Copy, Clone)]
#[repr(simd)]
struct Simd<T, const N: usize>([T; N]);
fn main() {
unsafe {
let mut arr = [4u8, 5, 6, 7];
let default = Simd::<u8, 4>([9; 4]);
let _x: Simd<u8, 2> = simd_masked_load(
Simd::<i8, 4>([-1, 0, -1, -1]),
arr.as_ptr(),
Simd::<u8, 4>([9; 4])
);
//~^^ ERROR mismatched types
let _x: Simd<u32, 4> = simd_masked_load(
Simd::<u8, 4>([1, 0, 1, 1]),
arr.as_ptr(),
default
);
//~^^ ERROR mismatched types
}
}

View file

@ -0,0 +1,59 @@
error[E0308]: mismatched types
--> $DIR/masked-load-store-check-fail.rs:21:13
|
LL | let _x: Simd<u8, 2> = simd_masked_load(
| ---------------- arguments to this function are incorrect
...
LL | Simd::<u8, 4>([9; 4])
| ^^^^^^^^^^^^^^^^^^^^^ expected `2`, found `4`
|
= note: expected struct `Simd<_, 2>`
found struct `Simd<_, 4>`
help: the return type of this call is `Simd<u8, 4>` due to the type of the argument passed
--> $DIR/masked-load-store-check-fail.rs:18:31
|
LL | let _x: Simd<u8, 2> = simd_masked_load(
| _______________________________^
LL | | Simd::<i8, 4>([-1, 0, -1, -1]),
LL | | arr.as_ptr(),
LL | | Simd::<u8, 4>([9; 4])
| | --------------------- this argument influences the return type of `simd_masked_load`
LL | | );
| |_________^
note: function defined here
--> $DIR/masked-load-store-check-fail.rs:5:8
|
LL | fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
| ^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/masked-load-store-check-fail.rs:28:13
|
LL | let _x: Simd<u32, 4> = simd_masked_load(
| ---------------- arguments to this function are incorrect
...
LL | default
| ^^^^^^^ expected `Simd<u32, 4>`, found `Simd<u8, 4>`
|
= note: expected struct `Simd<u32, _>`
found struct `Simd<u8, _>`
help: the return type of this call is `Simd<u8, 4>` due to the type of the argument passed
--> $DIR/masked-load-store-check-fail.rs:25:32
|
LL | let _x: Simd<u32, 4> = simd_masked_load(
| ________________________________^
LL | | Simd::<u8, 4>([1, 0, 1, 1]),
LL | | arr.as_ptr(),
LL | | default
| | ------- this argument influences the return type of `simd_masked_load`
LL | | );
| |_________^
note: function defined here
--> $DIR/masked-load-store-check-fail.rs:5:8
|
LL | fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
| ^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,33 @@
// run-pass
#![feature(repr_simd, platform_intrinsics)]
extern "platform-intrinsic" {
fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T) -> ();
}
#[derive(Copy, Clone)]
#[repr(simd)]
struct Simd<T, const N: usize>([T; N]);
fn main() {
unsafe {
let a = Simd::<u8, 4>([0, 1, 2, 3]);
let b_src = [4u8, 5, 6, 7];
let b_default = Simd::<u8, 4>([9; 4]);
let b: Simd::<u8, 4> = simd_masked_load(
Simd::<i8, 4>([-1, 0, -1, -1]),
b_src.as_ptr(),
b_default
);
assert_eq!(&b.0, &[4, 9, 6, 7]);
let mut output = [u8::MAX; 5];
simd_masked_store(Simd::<i8, 4>([-1, -1, -1, 0]), output.as_mut_ptr(), a);
assert_eq!(&output, &[0, 1, 2, u8::MAX, u8::MAX]);
simd_masked_store(Simd::<i8, 4>([0, -1, -1, 0]), output[1..].as_mut_ptr(), b);
assert_eq!(&output, &[0, 1, 9, 6, u8::MAX]);
}
}