Merge ref 'cb79c42008' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: cb79c42008
Filtered ref: 3d67cb5b8f2db0234afa897808f69bf76143044e
Upstream diff: f51d1bcdc6...cb79c42008

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The Miri Cronjob Bot 2025-12-21 05:06:32 +00:00
commit 346e02a75a
91 changed files with 934 additions and 580 deletions

View file

@ -714,7 +714,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
},
fields: FieldsShape::Arbitrary {
offsets: [niche_offset].into(),
memory_index: [0].into(),
in_memory_order: [FieldIdx::new(0)].into(),
},
backend_repr: abi,
largest_niche,
@ -1008,8 +1008,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let pair =
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar);
let pair_offsets = match pair.fields {
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
assert_eq!(memory_index.raw, [0, 1]);
FieldsShape::Arbitrary { ref offsets, ref in_memory_order } => {
assert_eq!(in_memory_order.raw, [FieldIdx::new(0), FieldIdx::new(1)]);
offsets
}
_ => panic!("encountered a non-arbitrary layout during enum layout"),
@ -1061,7 +1061,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
},
fields: FieldsShape::Arbitrary {
offsets: [Size::ZERO].into(),
memory_index: [0].into(),
in_memory_order: [FieldIdx::new(0)].into(),
},
largest_niche,
uninhabited,
@ -1110,10 +1110,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let pack = repr.pack;
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
let mut max_repr_align = repr.align;
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
let mut in_memory_order: IndexVec<u32, FieldIdx> = fields.indices().collect();
let optimize_field_order = !repr.inhibit_struct_field_reordering();
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
let optimizing = &mut inverse_memory_index.raw[..end];
let optimizing = &mut in_memory_order.raw[..end];
let fields_excluding_tail = &fields.raw[..end];
// unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts.
let field_seed = fields_excluding_tail
@ -1248,12 +1248,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
// regardless of the status of `-Z randomize-layout`
}
}
// inverse_memory_index holds field indices by increasing memory offset.
// That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
// in_memory_order holds field indices by increasing memory offset.
// That is, if field 5 has offset 0, the first element of in_memory_order is 5.
// We now write field offsets to the corresponding offset slot;
// field 5 with offset 0 puts 0 in offsets[5].
// At the bottom of this function, we invert `inverse_memory_index` to
// produce `memory_index` (see `invert_mapping`).
let mut unsized_field = None::<&F>;
let mut offsets = IndexVec::from_elem(Size::ZERO, fields);
let mut offset = Size::ZERO;
@ -1265,7 +1263,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
align = align.max(prefix_align);
offset = prefix_size.align_to(prefix_align);
}
for &i in &inverse_memory_index {
for &i in &in_memory_order {
let field = &fields[i];
if let Some(unsized_field) = unsized_field {
return Err(LayoutCalculatorError::UnexpectedUnsized(*unsized_field));
@ -1322,18 +1320,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
debug!("univariant min_size: {:?}", offset);
let min_size = offset;
// As stated above, inverse_memory_index holds field indices by increasing offset.
// This makes it an already-sorted view of the offsets vec.
// To invert it, consider:
// If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
// Field 5 would be the first element, so memory_index is i:
// Note: if we didn't optimize, it's already right.
let memory_index = if optimize_field_order {
inverse_memory_index.invert_bijective_mapping()
} else {
debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
inverse_memory_index.into_iter().map(|it| it.index() as u32).collect()
};
let size = min_size.align_to(align);
// FIXME(oli-obk): deduplicate and harden these checks
if size.bytes() >= dl.obj_size_bound() {
@ -1389,8 +1375,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let pair =
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b);
let pair_offsets = match pair.fields {
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
assert_eq!(memory_index.raw, [0, 1]);
FieldsShape::Arbitrary { ref offsets, ref in_memory_order } => {
assert_eq!(
in_memory_order.raw,
[FieldIdx::new(0), FieldIdx::new(1)]
);
offsets
}
FieldsShape::Primitive
@ -1434,7 +1423,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
Ok(LayoutData {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary { offsets, memory_index },
fields: FieldsShape::Arbitrary { offsets, in_memory_order },
backend_repr: abi,
largest_niche,
uninhabited,
@ -1530,7 +1519,10 @@ where
Ok(LayoutData {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() },
fields: FieldsShape::Arbitrary {
offsets: [Size::ZERO].into(),
in_memory_order: [FieldIdx::new(0)].into(),
},
backend_repr: repr,
largest_niche: elt.largest_niche,
uninhabited: false,

View file

@ -182,33 +182,29 @@ pub(super) fn layout<
// CoroutineLayout.
debug!("prefix = {:#?}", prefix);
let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
FieldsShape::Arbitrary { mut offsets, memory_index } => {
let mut inverse_memory_index = memory_index.invert_bijective_mapping();
FieldsShape::Arbitrary { mut offsets, in_memory_order } => {
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to
// "outer" and "promoted" fields respectively.
let b_start = tag_index.plus(1);
let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index()));
let offsets_a = offsets;
// Disentangle the "a" and "b" components of `inverse_memory_index`
// Disentangle the "a" and "b" components of `in_memory_order`
// by preserving the order but keeping only one disjoint "half" each.
// FIXME(eddyb) build a better abstraction for permutations, if possible.
let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index
.iter()
.filter_map(|&i| i.index().checked_sub(b_start.index()).map(FieldIdx::new))
.collect();
inverse_memory_index.raw.retain(|&i| i.index() < b_start.index());
let inverse_memory_index_a = inverse_memory_index;
// Since `inverse_memory_index_{a,b}` each only refer to their
// respective fields, they can be safely inverted
let memory_index_a = inverse_memory_index_a.invert_bijective_mapping();
let memory_index_b = inverse_memory_index_b.invert_bijective_mapping();
let mut in_memory_order_a = IndexVec::<u32, FieldIdx>::new();
let mut in_memory_order_b = IndexVec::<u32, FieldIdx>::new();
for i in in_memory_order {
if let Some(j) = i.index().checked_sub(b_start.index()) {
in_memory_order_b.push(FieldIdx::new(j));
} else {
in_memory_order_a.push(i);
}
}
let outer_fields =
FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
(outer_fields, offsets_b, memory_index_b)
FieldsShape::Arbitrary { offsets: offsets_a, in_memory_order: in_memory_order_a };
(outer_fields, offsets_b, in_memory_order_b.invert_bijective_mapping())
}
_ => unreachable!(),
};
@ -236,7 +232,7 @@ pub(super) fn layout<
)?;
variant.variants = Variants::Single { index };
let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
let FieldsShape::Arbitrary { offsets, in_memory_order } = variant.fields else {
unreachable!();
};
@ -249,8 +245,9 @@ pub(super) fn layout<
// promoted fields were being used, but leave the elements not in the
// subset as `invalid_field_idx`, which we can filter out later to
// obtain a valid (bijective) mapping.
let memory_index = in_memory_order.invert_bijective_mapping();
let invalid_field_idx = promoted_memory_index.len() + memory_index.len();
let mut combined_inverse_memory_index =
let mut combined_in_memory_order =
IndexVec::from_elem_n(FieldIdx::new(invalid_field_idx), invalid_field_idx);
let mut offsets_and_memory_index = iter::zip(offsets, memory_index);
@ -268,19 +265,18 @@ pub(super) fn layout<
(promoted_offsets[field_idx], promoted_memory_index[field_idx])
}
};
combined_inverse_memory_index[memory_index] = i;
combined_in_memory_order[memory_index] = i;
offset
})
.collect();
// Remove the unused slots and invert the mapping to obtain the
// combined `memory_index` (also see previous comment).
combined_inverse_memory_index.raw.retain(|&i| i.index() != invalid_field_idx);
let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping();
// Remove the unused slots to obtain the combined `in_memory_order`
// (also see previous comment).
combined_in_memory_order.raw.retain(|&i| i.index() != invalid_field_idx);
variant.fields = FieldsShape::Arbitrary {
offsets: combined_offsets,
memory_index: combined_memory_index,
in_memory_order: combined_in_memory_order,
};
size = size.max(variant.size);

View file

@ -16,7 +16,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary {
offsets: IndexVec::new(),
memory_index: IndexVec::new(),
in_memory_order: IndexVec::new(),
},
backend_repr: BackendRepr::Memory { sized },
largest_niche: None,
@ -108,7 +108,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary {
offsets: [Size::ZERO, b_offset].into(),
memory_index: [0, 1].into(),
in_memory_order: [FieldIdx::new(0), FieldIdx::new(1)].into(),
},
backend_repr: BackendRepr::ScalarPair(a, b),
largest_niche,
@ -133,7 +133,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
Some(fields) => FieldsShape::Union(fields),
None => FieldsShape::Arbitrary {
offsets: IndexVec::new(),
memory_index: IndexVec::new(),
in_memory_order: IndexVec::new(),
},
},
backend_repr: BackendRepr::Memory { sized: true },

View file

@ -1636,19 +1636,14 @@ pub enum FieldsShape<FieldIdx: Idx> {
// FIXME(eddyb) use small vector optimization for the common case.
offsets: IndexVec<FieldIdx, Size>,
/// Maps source order field indices to memory order indices,
/// Maps memory order field indices to source order indices,
/// depending on how the fields were reordered (if at all).
/// This is a permutation, with both the source order and the
/// memory order using the same (0..n) index ranges.
///
/// Note that during computation of `memory_index`, sometimes
/// it is easier to operate on the inverse mapping (that is,
/// from memory order to source order), and that is usually
/// named `inverse_memory_index`.
///
// FIXME(eddyb) build a better abstraction for permutations, if possible.
// FIXME(camlorn) also consider small vector optimization here.
memory_index: IndexVec<FieldIdx, u32>,
in_memory_order: IndexVec<u32, FieldIdx>,
},
}
@ -1682,51 +1677,17 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
}
}
#[inline]
pub fn memory_index(&self, i: usize) -> usize {
match *self {
FieldsShape::Primitive => {
unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
}
FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
FieldsShape::Arbitrary { ref memory_index, .. } => {
memory_index[FieldIdx::new(i)].try_into().unwrap()
}
}
}
/// Gets source indices of the fields by increasing offsets.
#[inline]
pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> {
let mut inverse_small = [0u8; 64];
let mut inverse_big = IndexVec::new();
let use_small = self.count() <= inverse_small.len();
// We have to write this logic twice in order to keep the array small.
if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
if use_small {
for (field_idx, &mem_idx) in memory_index.iter_enumerated() {
inverse_small[mem_idx as usize] = field_idx.index() as u8;
}
} else {
inverse_big = memory_index.invert_bijective_mapping();
}
}
// Primitives don't really have fields in the way that structs do,
// but having this return an empty iterator for them is unhelpful
// since that makes them look kinda like ZSTs, which they're not.
let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() };
(0..pseudofield_count).map(move |i| match *self {
(0..pseudofield_count).map(move |i| match self {
FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
FieldsShape::Arbitrary { .. } => {
if use_small {
inverse_small[i] as usize
} else {
inverse_big[i as u32].index()
}
}
FieldsShape::Arbitrary { in_memory_order, .. } => in_memory_order[i as u32].index(),
})
}
}

View file

@ -690,6 +690,16 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
}
}
pub(crate) struct ThreadLocalParser;
impl<S: Stage> NoArgsAttributeParser<S> for ThreadLocalParser {
const PATH: &[Symbol] = &[sym::thread_local];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
}
pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {

View file

@ -23,7 +23,7 @@ use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser,
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
TrackCallerParser, UsedParser,
ThreadLocalParser, TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::{
@ -269,6 +269,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
Single<WithoutArgs<ThreadLocalParser>>,
Single<WithoutArgs<TrackCallerParser>>,
Single<WithoutArgs<TypeConstParser>>,
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,

View file

@ -1275,29 +1275,81 @@ impl<'tcx> RegionInferenceContext<'tcx> {
shorter_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
) -> RegionRelationCheckResult {
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements
// Shrink `longer_fr` until we find a non-local region (if we do).
// We'll call it `fr-` -- it's ever so slightly smaller than
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
// Shrink `longer_fr` until we find some non-local regions.
// We'll call them `longer_fr-` -- they are ever so slightly smaller than
// `longer_fr`.
&& let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
{
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
let longer_fr_minus = self.universal_region_relations.non_local_lower_bounds(longer_fr);
debug!("try_propagate_universal_region_error: fr_minus={:?}", longer_fr_minus);
// If we don't find a any non-local regions, we should error out as there is nothing
// to propagate.
if longer_fr_minus.is_empty() {
return RegionRelationCheckResult::Error;
}
let blame_constraint = self
.best_blame_constraint(longer_fr, NllRegionVariableOrigin::FreeRegion, shorter_fr)
.0;
// Grow `shorter_fr` until we find some non-local regions. (We
// always will.) We'll call them `shorter_fr+` -- they're ever
// so slightly larger than `shorter_fr`.
// Grow `shorter_fr` until we find some non-local regions.
// We will always find at least one: `'static`. We'll call
// them `shorter_fr+` -- they're ever so slightly larger
// than `shorter_fr`.
let shorter_fr_plus =
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
for fr in shorter_fr_plus {
// Push the constraint `fr-: shorter_fr+`
// We then create constraints `longer_fr-: shorter_fr+` that may or may not
// be propagated (see below).
let mut constraints = vec![];
for fr_minus in longer_fr_minus {
for shorter_fr_plus in &shorter_fr_plus {
constraints.push((fr_minus, *shorter_fr_plus));
}
}
// We only need to propagate at least one of the constraints for
// soundness. However, we want to avoid arbitrary choices here
// and currently don't support returning OR constraints.
//
// If any of the `shorter_fr+` regions are already outlived by `longer_fr-`,
// we propagate only those.
//
// Consider this example (`'b: 'a` == `a -> b`), where we try to propagate `'d: 'a`:
// a --> b --> d
// \
// \-> c
// Here, `shorter_fr+` of `'a` == `['b, 'c]`.
// Propagating `'d: 'b` is correct and should occur; `'d: 'c` is redundant because of
// `'d: 'b` and could reject valid code.
//
// So we filter the constraints to regions already outlived by `longer_fr-`, but if
// the filter yields an empty set, we fall back to the original one.
let subset: Vec<_> = constraints
.iter()
.filter(|&&(fr_minus, shorter_fr_plus)| {
self.eval_outlives(fr_minus, shorter_fr_plus)
})
.copied()
.collect();
let propagated_constraints = if subset.is_empty() { constraints } else { subset };
debug!(
"try_propagate_universal_region_error: constraints={:?}",
propagated_constraints
);
assert!(
!propagated_constraints.is_empty(),
"Expected at least one constraint to propagate here"
);
for (fr_minus, fr_plus) in propagated_constraints {
// Push the constraint `long_fr-: shorter_fr+`
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject: ClosureOutlivesSubject::Region(fr_minus),
outlived_free_region: fr,
outlived_free_region: fr_plus,
blame_span: blame_constraint.cause.span,
category: blame_constraint.category,
});

View file

@ -94,28 +94,10 @@ impl UniversalRegionRelations<'_> {
/// words, returns the largest (*) known region `fr1` that (a) is
/// outlived by `fr` and (b) is not local.
///
/// (*) If there are multiple competing choices, we pick the "postdominating"
/// one. See `TransitiveRelation::postdom_upper_bound` for details.
pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
/// (*) If there are multiple competing choices, we return all of them.
pub(crate) fn non_local_lower_bounds(&self, fr: RegionVid) -> Vec<RegionVid> {
debug!("non_local_lower_bound(fr={:?})", fr);
let lower_bounds = self.non_local_bounds(&self.outlives, fr);
// In case we find more than one, reduce to one for
// convenience. This is to prevent us from generating more
// complex constraints, but it will cause spurious errors.
let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
debug!("non_local_bound: post_dom={:?}", post_dom);
post_dom.and_then(|post_dom| {
// If the mutual immediate postdom is not local, then
// there is no non-local result we can return.
if !self.universal_regions.is_local_free_region(post_dom) {
Some(post_dom)
} else {
None
}
})
self.non_local_bounds(&self.outlives, fr)
}
/// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`.

View file

@ -10,7 +10,7 @@
//! function u0:22(i64) -> i8, i8 system_v {
//! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd361e9f5c3d1c4deE
//! ; instance Instance { def: Item(DefId(0:42 ~ example[3895]::{impl#0}::call_once)), args: ['{erased}, '{erased}] }
//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: Memory { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 12266848898570219025 } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false }
//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: Memory { sized: true }, fields: Arbitrary { offsets: [], in_memory_order: [] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 12266848898570219025 } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], in_memory_order: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false }
//!
//! ; kind loc.idx param pass mode ty
//! ; ssa _0 (u8, u8) 2b 1 var=(0, 1)
@ -41,7 +41,7 @@
//! ;
//! ; _0 = <IsNotEmpty as mini_core::FnMut<(&&[u16],)>>::call_mut(move _3, copy _2)
//! v2 = stack_load.i64 ss0
//! ; abi: FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: &mut IsNotEmpty, layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(1 bytes)) }) }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false }
//! ; abi: FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: &mut IsNotEmpty, layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(1 bytes)) }) }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], in_memory_order: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false }
//! v3, v4 = call fn0(v1, v2) ; v1 = 1
//! v5 -> v3
//! v6 -> v4

View file

@ -707,8 +707,7 @@ pub(crate) unsafe fn llvm_optimize(
if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Enable) {
let cx =
SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size);
// For now we only support up to 10 kernels named kernel_0 ... kernel_9, a follow-up PR is
// introducing a proper offload intrinsic to solve this limitation.
for func in cx.get_functions() {
let offload_kernel = "offload-kernel";
if attributes::has_string_attr(func, offload_kernel) {

View file

@ -23,13 +23,14 @@ use rustc_middle::dep_graph;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrs, SanitizerFnAttrs};
use rustc_middle::mir::mono::Visibility;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
use rustc_session::config::{DebugInfo, Offload};
use rustc_span::Symbol;
use rustc_target::spec::SanitizerSet;
use super::ModuleLlvm;
use crate::attributes;
use crate::builder::Builder;
use crate::builder::gpu_offload::OffloadGlobals;
use crate::context::CodegenCx;
use crate::llvm::{self, Value};
@ -85,6 +86,19 @@ pub(crate) fn compile_codegen_unit(
let llvm_module = ModuleLlvm::new(tcx, cgu_name.as_str());
{
let mut cx = CodegenCx::new(tcx, cgu, &llvm_module);
// Declare and store globals shared by all offload kernels
//
// These globals are left in the LLVM-IR host module so all kernels can access them.
// They are necessary for correct offload execution. We do this here to simplify the
// `offload` intrinsic, avoiding the need for tracking whether it's the first
// intrinsic call or not.
if cx.sess().opts.unstable_opts.offload.contains(&Offload::Enable)
&& !cx.sess().target.is_like_gpu
{
cx.offload_globals.replace(Some(OffloadGlobals::declare(&cx)));
}
let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
for &(mono_item, data) in &mono_items {
mono_item.predefine::<Builder<'_, '_, '_>>(

View file

@ -2,17 +2,76 @@ use std::ffi::CString;
use llvm::Linkage::*;
use rustc_abi::Align;
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
use rustc_middle::ty::offload_meta::OffloadMetadata;
use crate::builder::SBuilder;
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::llvm::AttributePlace::Function;
use crate::llvm::{self, BasicBlock, Linkage, Type, Value};
use crate::llvm::{self, Linkage, Type, Value};
use crate::{SimpleCx, attributes};
// LLVM kernel-independent globals required for offloading
pub(crate) struct OffloadGlobals<'ll> {
pub launcher_fn: &'ll llvm::Value,
pub launcher_ty: &'ll llvm::Type,
pub bin_desc: &'ll llvm::Type,
pub kernel_args_ty: &'ll llvm::Type,
pub offload_entry_ty: &'ll llvm::Type,
pub begin_mapper: &'ll llvm::Value,
pub end_mapper: &'ll llvm::Value,
pub mapper_fn_ty: &'ll llvm::Type,
pub ident_t_global: &'ll llvm::Value,
pub register_lib: &'ll llvm::Value,
pub unregister_lib: &'ll llvm::Value,
pub init_rtls: &'ll llvm::Value,
}
impl<'ll> OffloadGlobals<'ll> {
pub(crate) fn declare(cx: &CodegenCx<'ll, '_>) -> Self {
let (launcher_fn, launcher_ty) = generate_launcher(cx);
let kernel_args_ty = KernelArgsTy::new_decl(cx);
let offload_entry_ty = TgtOffloadEntry::new_decl(cx);
let (begin_mapper, _, end_mapper, mapper_fn_ty) = gen_tgt_data_mappers(cx);
let ident_t_global = generate_at_one(cx);
let tptr = cx.type_ptr();
let ti32 = cx.type_i32();
let tgt_bin_desc_ty = vec![ti32, tptr, tptr, tptr];
let bin_desc = cx.type_named_struct("struct.__tgt_bin_desc");
cx.set_struct_body(bin_desc, &tgt_bin_desc_ty, false);
let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", mapper_fn_ty);
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", mapper_fn_ty);
let init_ty = cx.type_func(&[], cx.type_void());
let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty);
OffloadGlobals {
launcher_fn,
launcher_ty,
bin_desc,
kernel_args_ty,
offload_entry_ty,
begin_mapper,
end_mapper,
mapper_fn_ty,
ident_t_global,
register_lib,
unregister_lib,
init_rtls,
}
}
}
// ; Function Attrs: nounwind
// declare i32 @__tgt_target_kernel(ptr, i64, i32, i32, ptr, ptr) #2
fn generate_launcher<'ll>(cx: &'ll SimpleCx<'_>) -> (&'ll llvm::Value, &'ll llvm::Type) {
fn generate_launcher<'ll>(cx: &CodegenCx<'ll, '_>) -> (&'ll llvm::Value, &'ll llvm::Type) {
let tptr = cx.type_ptr();
let ti64 = cx.type_i64();
let ti32 = cx.type_i32();
@ -30,7 +89,7 @@ fn generate_launcher<'ll>(cx: &'ll SimpleCx<'_>) -> (&'ll llvm::Value, &'ll llvm
// @1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @0 }, align 8
// FIXME(offload): @0 should include the file name (e.g. lib.rs) in which the function to be
// offloaded was defined.
fn generate_at_one<'ll>(cx: &'ll SimpleCx<'_>) -> &'ll llvm::Value {
pub(crate) fn generate_at_one<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll llvm::Value {
let unknown_txt = ";unknown;unknown;0;0;;";
let c_entry_name = CString::new(unknown_txt).unwrap();
let c_val = c_entry_name.as_bytes_with_nul();
@ -68,7 +127,7 @@ pub(crate) struct TgtOffloadEntry {
}
impl TgtOffloadEntry {
pub(crate) fn new_decl<'ll>(cx: &'ll SimpleCx<'_>) -> &'ll llvm::Type {
pub(crate) fn new_decl<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll llvm::Type {
let offload_entry_ty = cx.type_named_struct("struct.__tgt_offload_entry");
let tptr = cx.type_ptr();
let ti64 = cx.type_i64();
@ -82,7 +141,7 @@ impl TgtOffloadEntry {
}
fn new<'ll>(
cx: &'ll SimpleCx<'_>,
cx: &CodegenCx<'ll, '_>,
region_id: &'ll Value,
llglobal: &'ll Value,
) -> [&'ll Value; 9] {
@ -126,7 +185,7 @@ impl KernelArgsTy {
const OFFLOAD_VERSION: u64 = 3;
const FLAGS: u64 = 0;
const TRIPCOUNT: u64 = 0;
fn new_decl<'ll>(cx: &'ll SimpleCx<'_>) -> &'ll Type {
fn new_decl<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
let kernel_arguments_ty = cx.type_named_struct("struct.__tgt_kernel_arguments");
let tptr = cx.type_ptr();
let ti64 = cx.type_i64();
@ -140,8 +199,8 @@ impl KernelArgsTy {
kernel_arguments_ty
}
fn new<'ll>(
cx: &'ll SimpleCx<'_>,
fn new<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
num_args: u64,
memtransfer_types: &'ll Value,
geps: [&'ll Value; 3],
@ -171,7 +230,8 @@ impl KernelArgsTy {
}
// Contains LLVM values needed to manage offloading for a single kernel.
pub(crate) struct OffloadKernelData<'ll> {
#[derive(Copy, Clone)]
pub(crate) struct OffloadKernelGlobals<'ll> {
pub offload_sizes: &'ll llvm::Value,
pub memtransfer_types: &'ll llvm::Value,
pub region_id: &'ll llvm::Value,
@ -179,7 +239,7 @@ pub(crate) struct OffloadKernelData<'ll> {
}
fn gen_tgt_data_mappers<'ll>(
cx: &'ll SimpleCx<'_>,
cx: &CodegenCx<'ll, '_>,
) -> (&'ll llvm::Value, &'ll llvm::Value, &'ll llvm::Value, &'ll llvm::Type) {
let tptr = cx.type_ptr();
let ti64 = cx.type_i64();
@ -241,12 +301,18 @@ pub(crate) fn add_global<'ll>(
// mapped to/from the gpu. It also returns a region_id with the name of this kernel, to be
// concatenated into the list of region_ids.
pub(crate) fn gen_define_handling<'ll>(
cx: &SimpleCx<'ll>,
offload_entry_ty: &'ll llvm::Type,
cx: &CodegenCx<'ll, '_>,
metadata: &[OffloadMetadata],
types: &[&Type],
symbol: &str,
) -> OffloadKernelData<'ll> {
types: &[&'ll Type],
symbol: String,
offload_globals: &OffloadGlobals<'ll>,
) -> OffloadKernelGlobals<'ll> {
if let Some(entry) = cx.offload_kernel_cache.borrow().get(&symbol) {
return *entry;
}
let offload_entry_ty = offload_globals.offload_entry_ty;
// It seems like non-pointer values are automatically mapped. So here, we focus on pointer (or
// reference) types.
let ptr_meta = types.iter().zip(metadata).filter_map(|(&x, meta)| match cx.type_kind(x) {
@ -272,9 +338,9 @@ pub(crate) fn gen_define_handling<'ll>(
let name = format!(".{symbol}.region_id");
let initializer = cx.get_const_i8(0);
let region_id = add_unnamed_global(&cx, &name, initializer, WeakAnyLinkage);
let region_id = add_global(&cx, &name, initializer, WeakAnyLinkage);
let c_entry_name = CString::new(symbol).unwrap();
let c_entry_name = CString::new(symbol.clone()).unwrap();
let c_val = c_entry_name.as_bytes_with_nul();
let offload_entry_name = format!(".offloading.entry_name.{symbol}");
@ -298,11 +364,16 @@ pub(crate) fn gen_define_handling<'ll>(
let c_section_name = CString::new("llvm_offload_entries").unwrap();
llvm::set_section(offload_entry, &c_section_name);
OffloadKernelData { offload_sizes, memtransfer_types, region_id, offload_entry }
let result =
OffloadKernelGlobals { offload_sizes, memtransfer_types, region_id, offload_entry };
cx.offload_kernel_cache.borrow_mut().insert(symbol, result);
result
}
fn declare_offload_fn<'ll>(
cx: &'ll SimpleCx<'_>,
cx: &CodegenCx<'ll, '_>,
name: &str,
ty: &'ll llvm::Type,
) -> &'ll llvm::Value {
@ -335,28 +406,28 @@ fn declare_offload_fn<'ll>(
// 4. set insert point after kernel call.
// 5. generate all the GEPS and stores, to be used in 6)
// 6. generate __tgt_target_data_end calls to move data from the GPU
pub(crate) fn gen_call_handling<'ll>(
cx: &SimpleCx<'ll>,
bb: &BasicBlock,
offload_data: &OffloadKernelData<'ll>,
pub(crate) fn gen_call_handling<'ll, 'tcx>(
builder: &mut Builder<'_, 'll, 'tcx>,
offload_data: &OffloadKernelGlobals<'ll>,
args: &[&'ll Value],
types: &[&Type],
metadata: &[OffloadMetadata],
offload_globals: &OffloadGlobals<'ll>,
) {
let OffloadKernelData { offload_sizes, offload_entry, memtransfer_types, region_id } =
let cx = builder.cx;
let OffloadKernelGlobals { offload_sizes, offload_entry, memtransfer_types, region_id } =
offload_data;
let (tgt_decl, tgt_target_kernel_ty) = generate_launcher(&cx);
let tgt_decl = offload_globals.launcher_fn;
let tgt_target_kernel_ty = offload_globals.launcher_ty;
// %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
let tptr = cx.type_ptr();
let ti32 = cx.type_i32();
let tgt_bin_desc_ty = vec![ti32, tptr, tptr, tptr];
let tgt_bin_desc = cx.type_named_struct("struct.__tgt_bin_desc");
cx.set_struct_body(tgt_bin_desc, &tgt_bin_desc_ty, false);
let tgt_bin_desc = offload_globals.bin_desc;
let tgt_kernel_decl = KernelArgsTy::new_decl(&cx);
let (begin_mapper_decl, _, end_mapper_decl, fn_ty) = gen_tgt_data_mappers(&cx);
let mut builder = SBuilder::build(cx, bb);
let tgt_kernel_decl = offload_globals.kernel_args_ty;
let begin_mapper_decl = offload_globals.begin_mapper;
let end_mapper_decl = offload_globals.end_mapper;
let fn_ty = offload_globals.mapper_fn_ty;
let num_args = types.len() as u64;
let ip = unsafe { llvm::LLVMRustGetInsertPoint(&builder.llbuilder) };
@ -378,9 +449,8 @@ pub(crate) fn gen_call_handling<'ll>(
// Step 0)
// %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
// %6 = alloca %struct.__tgt_bin_desc, align 8
let llfn = unsafe { llvm::LLVMGetBasicBlockParent(bb) };
unsafe {
llvm::LLVMRustPositionBuilderPastAllocas(&builder.llbuilder, llfn);
llvm::LLVMRustPositionBuilderPastAllocas(&builder.llbuilder, builder.llfn());
}
let tgt_bin_desc_alloca = builder.direct_alloca(tgt_bin_desc, Align::EIGHT, "EmptyDesc");
@ -413,16 +483,16 @@ pub(crate) fn gen_call_handling<'ll>(
}
let mapper_fn_ty = cx.type_func(&[cx.type_ptr()], cx.type_void());
let register_lib_decl = declare_offload_fn(&cx, "__tgt_register_lib", mapper_fn_ty);
let unregister_lib_decl = declare_offload_fn(&cx, "__tgt_unregister_lib", mapper_fn_ty);
let register_lib_decl = offload_globals.register_lib;
let unregister_lib_decl = offload_globals.unregister_lib;
let init_ty = cx.type_func(&[], cx.type_void());
let init_rtls_decl = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty);
let init_rtls_decl = offload_globals.init_rtls;
// FIXME(offload): Later we want to add them to the wrapper code, rather than our main function.
// call void @__tgt_register_lib(ptr noundef %6)
builder.call(mapper_fn_ty, register_lib_decl, &[tgt_bin_desc_alloca], None);
builder.call(mapper_fn_ty, None, None, register_lib_decl, &[tgt_bin_desc_alloca], None, None);
// call void @__tgt_init_all_rtls()
builder.call(init_ty, init_rtls_decl, &[], None);
builder.call(init_ty, None, None, init_rtls_decl, &[], None, None);
for i in 0..num_args {
let idx = cx.get_const_i32(i);
@ -437,15 +507,15 @@ pub(crate) fn gen_call_handling<'ll>(
// For now we have a very simplistic indexing scheme into our
// offload_{baseptrs,ptrs,sizes}. We will probably improve this along with our gpu frontend pr.
fn get_geps<'a, 'll>(
builder: &mut SBuilder<'a, 'll>,
cx: &'ll SimpleCx<'ll>,
fn get_geps<'ll, 'tcx>(
builder: &mut Builder<'_, 'll, 'tcx>,
ty: &'ll Type,
ty2: &'ll Type,
a1: &'ll Value,
a2: &'ll Value,
a4: &'ll Value,
) -> [&'ll Value; 3] {
let cx = builder.cx;
let i32_0 = cx.get_const_i32(0);
let gep1 = builder.inbounds_gep(ty, a1, &[i32_0, i32_0]);
@ -454,9 +524,8 @@ pub(crate) fn gen_call_handling<'ll>(
[gep1, gep2, gep3]
}
fn generate_mapper_call<'a, 'll>(
builder: &mut SBuilder<'a, 'll>,
cx: &'ll SimpleCx<'ll>,
fn generate_mapper_call<'ll, 'tcx>(
builder: &mut Builder<'_, 'll, 'tcx>,
geps: [&'ll Value; 3],
o_type: &'ll Value,
fn_to_call: &'ll Value,
@ -464,20 +533,20 @@ pub(crate) fn gen_call_handling<'ll>(
num_args: u64,
s_ident_t: &'ll Value,
) {
let cx = builder.cx;
let nullptr = cx.const_null(cx.type_ptr());
let i64_max = cx.get_const_i64(u64::MAX);
let num_args = cx.get_const_i32(num_args);
let args =
vec![s_ident_t, i64_max, num_args, geps[0], geps[1], geps[2], o_type, nullptr, nullptr];
builder.call(fn_ty, fn_to_call, &args, None);
builder.call(fn_ty, None, None, fn_to_call, &args, None, None);
}
// Step 2)
let s_ident_t = generate_at_one(&cx);
let geps = get_geps(&mut builder, &cx, ty, ty2, a1, a2, a4);
let s_ident_t = offload_globals.ident_t_global;
let geps = get_geps(builder, ty, ty2, a1, a2, a4);
generate_mapper_call(
&mut builder,
&cx,
builder,
geps,
memtransfer_types,
begin_mapper_decl,
@ -504,14 +573,13 @@ pub(crate) fn gen_call_handling<'ll>(
region_id,
a5,
];
builder.call(tgt_target_kernel_ty, tgt_decl, &args, None);
builder.call(tgt_target_kernel_ty, None, None, tgt_decl, &args, None, None);
// %41 = call i32 @__tgt_target_kernel(ptr @1, i64 -1, i32 2097152, i32 256, ptr @.kernel_1.region_id, ptr %kernel_args)
// Step 4)
let geps = get_geps(&mut builder, &cx, ty, ty2, a1, a2, a4);
let geps = get_geps(builder, ty, ty2, a1, a2, a4);
generate_mapper_call(
&mut builder,
&cx,
builder,
geps,
memtransfer_types,
end_mapper_decl,
@ -520,7 +588,5 @@ pub(crate) fn gen_call_handling<'ll>(
s_ident_t,
);
builder.call(mapper_fn_ty, unregister_lib_decl, &[tgt_bin_desc_alloca], None);
drop(builder);
builder.call(mapper_fn_ty, None, None, unregister_lib_decl, &[tgt_bin_desc_alloca], None, None);
}

View file

@ -35,6 +35,7 @@ use smallvec::SmallVec;
use crate::abi::to_llvm_calling_convention;
use crate::back::write::to_llvm_code_model;
use crate::builder::gpu_offload::{OffloadGlobals, OffloadKernelGlobals};
use crate::callee::get_fn;
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
use crate::llvm::{self, Metadata, MetadataKindId, Module, Type, Value};
@ -156,6 +157,12 @@ pub(crate) struct FullCx<'ll, 'tcx> {
/// Cache of Objective-C selector references
pub objc_selrefs: RefCell<FxHashMap<Symbol, &'ll Value>>,
/// Globals shared by the offloading runtime
pub offload_globals: RefCell<Option<OffloadGlobals<'ll>>>,
/// Cache of kernel-specific globals
pub offload_kernel_cache: RefCell<FxHashMap<String, OffloadKernelGlobals<'ll>>>,
}
fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
@ -639,6 +646,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
objc_class_t: Cell::new(None),
objc_classrefs: Default::default(),
objc_selrefs: Default::default(),
offload_globals: Default::default(),
offload_kernel_cache: Default::default(),
},
PhantomData,
)

View file

@ -26,7 +26,7 @@ use tracing::debug;
use crate::abi::FnAbiLlvmExt;
use crate::builder::Builder;
use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
use crate::builder::gpu_offload::TgtOffloadEntry;
use crate::builder::gpu_offload::{gen_call_handling, gen_define_handling};
use crate::context::CodegenCx;
use crate::errors::{
AutoDiffWithoutEnable, AutoDiffWithoutLto, OffloadWithoutEnable, OffloadWithoutFatLTO,
@ -1295,8 +1295,6 @@ fn codegen_offload<'ll, 'tcx>(
let args = get_args_from_tuple(bx, args[1], fn_target);
let target_symbol = symbol_name_for_instance_in_crate(tcx, fn_target, LOCAL_CRATE);
let offload_entry_ty = TgtOffloadEntry::new_decl(&cx);
let sig = tcx.fn_sig(fn_target.def_id()).skip_binder().skip_binder();
let inputs = sig.inputs();
@ -1304,17 +1302,16 @@ fn codegen_offload<'ll, 'tcx>(
let types = inputs.iter().map(|ty| cx.layout_of(*ty).llvm_type(cx)).collect::<Vec<_>>();
let offload_data = crate::builder::gpu_offload::gen_define_handling(
cx,
offload_entry_ty,
&metadata,
&types,
&target_symbol,
);
// FIXME(Sa4dUs): pass the original builder once we separate kernel launch logic from globals
let bb = unsafe { llvm::LLVMGetInsertBlock(bx.llbuilder) };
crate::builder::gpu_offload::gen_call_handling(cx, bb, &offload_data, &args, &types, &metadata);
let offload_globals_ref = cx.offload_globals.borrow();
let offload_globals = match offload_globals_ref.as_ref() {
Some(globals) => globals,
None => {
// Offload is not initialized, cannot continue
return;
}
};
let offload_data = gen_define_handling(&cx, &metadata, &types, target_symbol, offload_globals);
gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals);
}
fn get_args_from_tuple<'ll, 'tcx>(

View file

@ -350,6 +350,9 @@ fn process_builtin_attrs(
codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM;
}
}
AttributeKind::ThreadLocal => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL
}
_ => {}
}
}
@ -366,7 +369,6 @@ fn process_builtin_attrs(
sym::rustc_allocator_zeroed => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
}
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::instruction_set => {
codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
}

View file

@ -561,8 +561,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
)?;
// Sanity-check that `eval_fn_call` either pushed a new frame or
// did a jump to another block.
if self.frame_idx() == old_stack && self.frame().loc == old_loc {
// did a jump to another block. We disable the sanity check for functions that
// can't return, since Miri sometimes does have to keep the location the same
// for those (which is fine since execution will continue on a different thread).
if target.is_some() && self.frame_idx() == old_stack && self.frame().loc == old_loc
{
span_bug!(terminator.source_info.span, "evaluating this call made no progress");
}
}

View file

@ -4,7 +4,7 @@
use std::num::NonZero;
use rustc_abi::{FieldIdx, FieldsShape, VariantIdx, Variants};
use rustc_index::IndexVec;
use rustc_index::{Idx as _, IndexVec};
use rustc_middle::mir::interpret::InterpResult;
use rustc_middle::ty::{self, Ty};
use tracing::trace;
@ -27,13 +27,15 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
/// This function provides the chance to reorder the order in which fields are visited for
/// `FieldsShape::Aggregate`.
///
/// The default means we iterate in source declaration order; alternatively this can do some
/// work with `memory_index` to iterate in memory order.
/// The default means we iterate in source declaration order; alternatively this can use
/// `in_memory_order` to iterate in memory order.
#[inline(always)]
fn aggregate_field_iter(
memory_index: &IndexVec<FieldIdx, u32>,
) -> impl Iterator<Item = FieldIdx> + 'static {
memory_index.indices()
in_memory_order: &IndexVec<u32, FieldIdx>,
) -> impl Iterator<Item = FieldIdx> {
// Allow the optimizer to elide the bounds checking when creating each index.
let _ = FieldIdx::new(in_memory_order.len());
(0..in_memory_order.len()).map(FieldIdx::new)
}
// Recursive actions, ready to be overloaded.
@ -168,8 +170,8 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
&FieldsShape::Union(fields) => {
self.visit_union(v, fields)?;
}
FieldsShape::Arbitrary { memory_index, .. } => {
for idx in Self::aggregate_field_iter(memory_index) {
FieldsShape::Arbitrary { in_memory_order, .. } => {
for idx in Self::aggregate_field_iter(in_memory_order) {
let field = self.ecx().project_field(v, idx)?;
self.visit_field(v, idx.as_usize(), &field)?;
}

View file

@ -1123,7 +1123,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(Word, List: &[r#""...""#]), DuplicatesOk,
EncodeCrossCrate::Yes,
),
rustc_attr!(
rustc_attr!(
rustc_offload_kernel, Normal,
template!(Word), DuplicatesOk,
EncodeCrossCrate::Yes,

View file

@ -1010,6 +1010,9 @@ pub enum AttributeKind {
/// `#[unsafe(force_target_feature(enable = "...")]`.
TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },
/// Represents `#[thread_local]`
ThreadLocal,
/// Represents `#[track_caller]`
TrackCaller(Span),

View file

@ -114,6 +114,7 @@ impl AttributeKind {
Stability { .. } => Yes,
StdInternalSymbol(..) => No,
TargetFeature { .. } => No,
ThreadLocal => No,
TrackCaller(..) => Yes,
TypeConst(..) => Yes,
TypeLengthLimit { .. } => No,

View file

@ -181,9 +181,6 @@ impl<I: Idx, J: Idx> IndexSlice<I, J> {
/// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`,
/// assuming the values in `self` are a permutation of `0..self.len()`.
///
/// This is used to go between `memory_index` (source field order to memory order)
/// and `inverse_memory_index` (memory order to source field order).
/// See also `FieldsShape::Arbitrary::memory_index` for more details.
// FIXME(eddyb) build a better abstraction for permutations, if possible.
pub fn invert_bijective_mapping(&self) -> IndexVec<J, I> {
debug_assert_eq!(

View file

@ -251,9 +251,7 @@ impl<'a> MissingNativeLibrary<'a> {
// if it looks like the user has provided a complete filename rather just the bare lib name,
// then provide a note that they might want to try trimming the name
let suggested_name = if !verbatim {
if let Some(libname) = libname.strip_prefix("lib")
&& let Some(libname) = libname.strip_suffix(".a")
{
if let Some(libname) = libname.strip_circumfix("lib", ".a") {
// this is a unix style filename so trim prefix & suffix
Some(libname)
} else if let Some(libname) = libname.strip_suffix(".lib") {

View file

@ -10,6 +10,7 @@
#![feature(never_type)]
#![feature(proc_macro_internals)]
#![feature(result_option_map_or_default)]
#![feature(strip_circumfix)]
#![feature(trusted_len)]
// tidy-alphabetical-end

View file

@ -484,10 +484,6 @@ passes_sanitize_attribute_not_allowed =
.no_body = function has no body
.help = sanitize attribute can be applied to a function (with body), impl block, or module
passes_should_be_applied_to_static =
attribute should be applied to a static
.label = not a static
passes_should_be_applied_to_trait =
attribute should be applied to a trait
.label = not a trait

View file

@ -297,6 +297,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
| AttributeKind::PinV2(..)
| AttributeKind::WindowsSubsystem(..)
| AttributeKind::ThreadLocal
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
@ -310,7 +311,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::diagnostic, sym::on_const, ..] => {
self.check_diagnostic_on_const(attr.span(), hir_id, target, item)
}
[sym::thread_local, ..] => self.check_thread_local(attr, span, target),
[sym::rustc_clean, ..]
| [sym::rustc_dirty, ..]
| [sym::rustc_if_this_changed, ..]
@ -768,19 +768,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
/// Checks if the `#[thread_local]` attribute on `item` is valid.
fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) {
match target {
Target::ForeignStatic | Target::Static => {}
_ => {
self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic {
attr_span: attr.span(),
defn_span: span,
});
}
}
}
fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) {
if let Some(location) = match target {
Target::AssocTy => {

View file

@ -98,15 +98,6 @@ pub(crate) struct AttrShouldBeAppliedToTrait {
pub defn_span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_should_be_applied_to_static)]
pub(crate) struct AttrShouldBeAppliedToStatic {
#[primary_span]
pub attr_span: Span,
#[label]
pub defn_span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_doc_alias_bad_location)]
pub(crate) struct DocAliasBadLocation<'a> {

View file

@ -241,12 +241,14 @@ bitflags::bitflags! {
}
impl<E: Encoder> Encodable<E> for RemapPathScopeComponents {
#[inline]
fn encode(&self, s: &mut E) {
s.emit_u8(self.bits());
}
}
impl<D: Decoder> Decodable<D> for RemapPathScopeComponents {
#[inline]
fn decode(s: &mut D) -> RemapPathScopeComponents {
RemapPathScopeComponents::from_bits(s.read_u8())
.expect("invalid bits for RemapPathScopeComponents")
@ -308,12 +310,13 @@ struct InnerRealFileName {
}
impl Hash for RealFileName {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
// To prevent #70924 from happening again we should only hash the
// remapped path if that exists. This is because remapped paths to
// sysroot crates (/rust/$hash or /rust/$version) remain stable even
// if the corresponding local path changes.
if !self.scopes.is_all() {
if !self.was_fully_remapped() {
self.local.hash(state);
}
self.maybe_remapped.hash(state);
@ -327,6 +330,7 @@ impl RealFileName {
/// ## Panic
///
/// Only one scope components can be given to this function.
#[inline]
pub fn path(&self, scope: RemapPathScopeComponents) -> &Path {
assert!(
scope.bits().count_ones() == 1,
@ -351,6 +355,7 @@ impl RealFileName {
/// ## Panic
///
/// Only one scope components can be given to this function.
#[inline]
pub fn embeddable_name(&self, scope: RemapPathScopeComponents) -> (&Path, &Path) {
assert!(
scope.bits().count_ones() == 1,
@ -369,26 +374,58 @@ impl RealFileName {
/// if this information exists.
///
/// May not exists if the filename was imported from another crate.
///
/// Avoid embedding this in build artifacts; prefer `path()` or `embeddable_name()`.
#[inline]
pub fn local_path(&self) -> Option<&Path> {
self.local.as_ref().map(|lp| lp.name.as_ref())
if self.was_not_remapped() {
Some(&self.maybe_remapped.name)
} else if let Some(local) = &self.local {
Some(&local.name)
} else {
None
}
}
/// Returns the path suitable for reading from the file system on the local host,
/// if this information exists.
///
/// May not exists if the filename was imported from another crate.
///
/// Avoid embedding this in build artifacts; prefer `path()` or `embeddable_name()`.
#[inline]
pub fn into_local_path(self) -> Option<PathBuf> {
self.local.map(|lp| lp.name)
if self.was_not_remapped() {
Some(self.maybe_remapped.name)
} else if let Some(local) = self.local {
Some(local.name)
} else {
None
}
}
/// Returns whenever the filename was remapped.
#[inline]
pub(crate) fn was_remapped(&self) -> bool {
!self.scopes.is_empty()
}
/// Returns whenever the filename was fully remapped.
#[inline]
fn was_fully_remapped(&self) -> bool {
self.scopes.is_all()
}
/// Returns whenever the filename was not remapped.
#[inline]
fn was_not_remapped(&self) -> bool {
self.scopes.is_empty()
}
/// Returns an empty `RealFileName`
///
/// Useful as the working directory input to `SourceMap::to_real_filename`.
#[inline]
pub fn empty() -> RealFileName {
RealFileName {
local: Some(InnerRealFileName {
@ -420,9 +457,14 @@ impl RealFileName {
/// Update the filename for encoding in the crate metadata.
///
/// Currently it's about removing the local part when the filename
/// is fully remapped.
/// is either fully remapped or not remapped at all.
#[inline]
pub fn update_for_crate_metadata(&mut self) {
if self.scopes.is_all() {
if self.was_fully_remapped() || self.was_not_remapped() {
// NOTE: This works because when the filename is fully
// remapped, we don't care about the `local` part,
// and when the filename is not remapped at all,
// `maybe_remapped` and `local` are equal.
self.local = None;
}
}
@ -529,6 +571,7 @@ impl FileName {
/// if this information exists.
///
/// Avoid embedding this in build artifacts. Prefer using the `display` method.
#[inline]
pub fn prefer_remapped_unconditionally(&self) -> FileNameDisplay<'_> {
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
}
@ -537,16 +580,19 @@ impl FileName {
/// if this information exists.
///
/// Avoid embedding this in build artifacts. Prefer using the `display` method.
#[inline]
pub fn prefer_local_unconditionally(&self) -> FileNameDisplay<'_> {
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
}
/// Returns a short (either the filename or an empty string).
#[inline]
pub fn short(&self) -> FileNameDisplay<'_> {
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Short }
}
/// Returns a `Display`-able path for the given scope.
#[inline]
pub fn display(&self, scope: RemapPathScopeComponents) -> FileNameDisplay<'_> {
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Scope(scope) }
}

View file

@ -2956,11 +2956,6 @@ impl Target {
matches!(self.linker_flavor, LinkerFlavor::Bpf),
"`linker_flavor` must be `bpf` if and only if `arch` is `bpf`"
);
check_eq!(
self.arch == Arch::Nvptx64,
matches!(self.linker_flavor, LinkerFlavor::Ptx),
"`linker_flavor` must be `ptc` if and only if `arch` is `nvptx64`"
);
for args in [
&self.pre_link_args,

View file

@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
arch: Arch::AArch64,
options: TargetOptions {
features: "+v8a".into(),
features: "+v8a,+outline-atomics".into(),
max_atomic_width: Some(128),
stack_probes: StackProbeType::Inline,
supported_sanitizers: SanitizerSet::ADDRESS

View file

@ -19,9 +19,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
os: Os::Cuda,
vendor: "nvidia".into(),
linker_flavor: LinkerFlavor::Ptx,
// The linker can be installed from `crates.io`.
linker: Some("rust-ptx-linker".into()),
linker_flavor: LinkerFlavor::Llbc,
// With `ptx-linker` approach, it can be later overridden via link flags.
cpu: "sm_30".into(),

View file

@ -1758,8 +1758,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// specify a byte literal
(ty::Uint(ty::UintTy::U8), ty::Char) => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
&& let Some(code) =
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
&& let Some(code) = code.strip_circumfix('\'', '\'')
// forbid all Unicode escapes
&& !code.starts_with("\\u")
// forbids literal Unicode characters beyond ASCII
@ -1776,7 +1775,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// specify a character literal (issue #92479)
(ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
&& let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
&& let Some(code) = code.strip_circumfix('"', '"')
&& code.chars().count() == 1
{
suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral {

View file

@ -22,6 +22,7 @@
#![feature(iter_intersperse)]
#![feature(iterator_try_reduce)]
#![feature(never_type)]
#![feature(strip_circumfix)]
#![feature(try_blocks)]
#![feature(unwrap_infallible)]
#![feature(yeet_expr)]

View file

@ -491,7 +491,7 @@ pub(crate) mod rustc {
) -> Result<Self, Err> {
// This constructor does not support non-`FieldsShape::Arbitrary`
// layouts.
let FieldsShape::Arbitrary { offsets, memory_index } = layout.fields() else {
let FieldsShape::Arbitrary { offsets, in_memory_order } = layout.fields() else {
return Err(Err::NotYetSupported);
};
@ -519,8 +519,7 @@ pub(crate) mod rustc {
}
// Append the fields, in memory order, to the layout.
let inverse_memory_index = memory_index.invert_bijective_mapping();
for &field_idx in inverse_memory_index.iter() {
for &field_idx in in_memory_order.iter() {
// Add interfield padding.
let padding_needed = offsets[field_idx] - size;
let padding = Self::padding(padding_needed.bytes_usize());

View file

@ -9,7 +9,7 @@ use rustc_abi::{
use rustc_hashes::Hash64;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::find_attr;
use rustc_index::IndexVec;
use rustc_index::{Idx as _, IndexVec};
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
@ -374,7 +374,7 @@ fn layout_of_uncached<'tcx>(
// specifically care about pattern types will have to handle it.
layout.fields = FieldsShape::Arbitrary {
offsets: [Size::ZERO].into_iter().collect(),
memory_index: [0].into_iter().collect(),
in_memory_order: [FieldIdx::new(0)].into_iter().collect(),
};
tcx.mk_layout(layout)
}

View file

@ -722,7 +722,6 @@ impl Step for Miri {
// miri tests need to know about the stage sysroot
cargo.env("MIRI_SYSROOT", &miri_sysroot);
cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
cargo.env("MIRI", &miri.tool_path);
// Set the target.
cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());

View file

@ -12,7 +12,7 @@ platform.
## Requirements
This target is `no_std` and will typically be built with crate-type `cdylib` and `-C linker-flavor=llbc`, which generates PTX.
This target is `no_std`, and uses the `llvm-bitcode-linker` by default. For PTX output, build with crate-type `cdylib`.
The necessary components for this workflow are:
- `rustup toolchain add nightly`
@ -38,7 +38,7 @@ While the compiler accepts `#[target_feature(enable = "ptx80", enable = "sm_89")
A `no_std` crate containing one or more functions with `extern "ptx-kernel"` can be compiled to PTX using a command like the following.
```console
$ RUSTFLAGS='-Ctarget-cpu=sm_89' cargo +nightly rustc --target=nvptx64-nvidia-cuda -Zbuild-std=core --crate-type=cdylib -- -Clinker-flavor=llbc -Zunstable-options
$ RUSTFLAGS='-Ctarget-cpu=sm_89' cargo +nightly rustc --target=nvptx64-nvidia-cuda -Zbuild-std=core --crate-type=cdylib
```
Intrinsics in `core::arch::nvptx` may use `#[cfg(target_feature = "...")]`, thus it's necessary to use `-Zbuild-std=core` with appropriate `RUSTFLAGS`. The following components are needed for this workflow:

View file

@ -14,7 +14,7 @@ use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::{BytePos, FileName, Symbol};
use rustc_span::{BytePos, FileName, RemapPathScopeComponents, Symbol};
use tracing::info;
use super::print_item::{full_path, print_item, print_item_path};
@ -365,7 +365,10 @@ impl<'tcx> Context<'tcx> {
// We can safely ignore synthetic `SourceFile`s.
let file = match span.filename(self.sess()) {
FileName::Real(ref path) => path.local_path()?.to_path_buf(),
FileName::Real(ref path) => path
.local_path()
.unwrap_or(path.path(RemapPathScopeComponents::MACRO))
.to_path_buf(),
_ => return None,
};
let file = &file;
@ -499,10 +502,12 @@ impl<'tcx> Context<'tcx> {
} = options;
let src_root = match krate.src(tcx) {
FileName::Real(ref p) => match p.local_path().map(|p| p.parent()).flatten() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
},
FileName::Real(ref p) => {
match p.local_path().unwrap_or(p.path(RemapPathScopeComponents::MACRO)).parent() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
}
}
_ => PathBuf::new(),
};
// If user passed in `--playground-url` arg, we fill in crate name here

@ -1 +1 @@
Subproject commit e91b2baa632c0c7e84216c91ecfe107c37d887c1
Subproject commit 3861f60f6b58f57524c0e7aab1f5c1ad83e35409

View file

@ -584,10 +584,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
fn aggregate_field_iter(
memory_index: &IndexVec<FieldIdx, u32>,
) -> impl Iterator<Item = FieldIdx> + 'static {
let inverse_memory_index = memory_index.invert_bijective_mapping();
inverse_memory_index.into_iter()
in_memory_order: &IndexVec<u32, FieldIdx>,
) -> impl Iterator<Item = FieldIdx> {
in_memory_order.iter().copied()
}
// Hook to detect `UnsafeCell`.

View file

@ -538,7 +538,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
code,
crate::concurrency::ExitType::ExitCalled,
)?;
todo!(); // FIXME(genmc): Add a way to return here that is allowed to not do progress (can't use existing EmulateItemResult variants).
return interp_ok(EmulateItemResult::AlreadyJumped);
}
throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
}

View file

@ -0,0 +1,9 @@
//@ compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows
fn main() {
std::thread::spawn(|| {
unsafe { std::hint::unreachable_unchecked() }; //~ERROR: entering unreachable code
});
// If we exit immediately, we might entirely miss the UB in the other thread.
std::process::exit(0);
}

View file

@ -0,0 +1,126 @@
Running GenMC Verification...
warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures.
--> RUSTLIB/std/src/thread/mod.rs:LL:CC
|
LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code
|
= note: BACKTRACE:
= note: inside `std::thread::ThreadId::new` at RUSTLIB/std/src/thread/mod.rs:LL:CC
= note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC
= note: inside `std::thread::current::id::get_or_init` at RUSTLIB/std/src/thread/current.rs:LL:CC
= note: inside `std::thread::current_id` at RUSTLIB/std/src/thread/current.rs:LL:CC
= note: inside `std::rt::init` at RUSTLIB/std/src/rt.rs:LL:CC
= note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
= note: inside `std::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
= note: inside `std::panicking::catch_unwind::<isize, {closure@std::rt::lang_start_internal::{closure#0}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
= note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
= note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC
= note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC
warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access.
--> RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
|
LL | || self
| ________________^
LL | | .state
LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed)
| |____________________________________________________________________________________^ GenMC might miss possible behaviors of this code
|
= note: BACKTRACE:
= note: inside `std::sys::sync::PLATFORM::futex::RwLock::read` at RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
= note: inside `std::sync::RwLock::<()>::read` at RUSTLIB/std/src/sync/poison/rwlock.rs:LL:CC
= note: inside `std::sys::env::PLATFORM::env_read_lock` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
= note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
= note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
= note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC
= note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC
= note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC
note: inside `main`
--> tests/genmc/fail/shims/exit.rs:LL:CC
|
LL | / std::thread::spawn(|| {
LL | | unsafe { std::hint::unreachable_unchecked() };
LL | | });
| |______^
warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures.
--> RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
|
LL | || self
| ________________^
LL | | .state
LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed)
| |____________________________________________________________________________________^ GenMC might miss possible behaviors of this code
|
= note: BACKTRACE:
= note: inside `std::sys::sync::PLATFORM::futex::RwLock::read` at RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC
= note: inside `std::sync::RwLock::<()>::read` at RUSTLIB/std/src/sync/poison/rwlock.rs:LL:CC
= note: inside `std::sys::env::PLATFORM::env_read_lock` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
= note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
= note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::<std::option::Option<std::ffi::OsString>>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC
= note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC
= note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC
= note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC
= note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC
note: inside `main`
--> tests/genmc/fail/shims/exit.rs:LL:CC
|
LL | / std::thread::spawn(|| {
LL | | unsafe { std::hint::unreachable_unchecked() };
LL | | });
| |______^
warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures.
--> RUSTLIB/std/src/rt.rs:LL:CC
|
LL | / CLEANUP.call_once(|| unsafe {
LL | | // Flush stdout and disable buffering.
LL | | crate::io::cleanup();
... |
LL | | });
| |______^ GenMC might miss possible behaviors of this code
|
= note: BACKTRACE:
= note: inside `std::rt::cleanup` at RUSTLIB/std/src/rt.rs:LL:CC
= note: inside `std::process::exit` at RUSTLIB/std/src/process.rs:LL:CC
note: inside `main`
--> tests/genmc/fail/shims/exit.rs:LL:CC
|
LL | std::process::exit(0);
| ^^^^^^^^^^^^^^^^^^^^^
warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access.
--> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC
|
LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code
|
= note: BACKTRACE:
= note: inside `std::sys::exit_guard::unique_thread_exit` at RUSTLIB/std/src/sys/exit_guard.rs:LL:CC
= note: inside `std::sys::pal::PLATFORM::os::exit` at RUSTLIB/std/src/sys/pal/PLATFORM/os.rs:LL:CC
= note: inside `std::process::exit` at RUSTLIB/std/src/process.rs:LL:CC
note: inside `main`
--> tests/genmc/fail/shims/exit.rs:LL:CC
|
LL | std::process::exit(0);
| ^^^^^^^^^^^^^^^^^^^^^
error: Undefined Behavior: entering unreachable code
--> tests/genmc/fail/shims/exit.rs:LL:CC
|
LL | unsafe { std::hint::unreachable_unchecked() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report
error: aborting due to 1 previous error; 5 warnings emitted

View file

@ -27,7 +27,7 @@ enum Mode {
}
fn miri_path() -> PathBuf {
PathBuf::from(env::var("MIRI").unwrap_or_else(|_| env!("CARGO_BIN_EXE_miri").into()))
env!("CARGO_BIN_EXE_miri").into()
}
// Build the shared object file for testing native function calls.

View file

@ -1,5 +1,5 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc
//@ compile-flags: --crate-type cdylib
//@ only-nvptx64
#![no_std]

View file

@ -1,5 +1,5 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_50 -Z unstable-options -Clinker-flavor=llbc
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_50
//@ only-nvptx64
#![no_std]

View file

@ -1,5 +1,5 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86
//@ only-nvptx64
// The PTX ABI stability is tied to major versions of the PTX ISA

View file

@ -1,5 +1,5 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86
//@ only-nvptx64
// The PTX ABI stability is tied to major versions of the PTX ISA

View file

@ -1,5 +1,5 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc
//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86
//@ only-nvptx64
// The following ABI tests are made with nvcc 11.6 does.

View file

@ -1,5 +1,5 @@
//@ assembly-output: ptx-linker
//@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc
//@ compile-flags: --crate-type cdylib
//@ only-nvptx64
//@ revisions: LLVM20 LLVM21
//@ [LLVM21] min-llvm-version: 21

View file

@ -11,6 +11,7 @@
// when inside of a function called main. This, too, is a temporary workaround for not having a
// frontend.
#![feature(rustc_attrs)]
#![feature(core_intrinsics)]
#![no_main]
@ -21,29 +22,31 @@ fn main() {
core::hint::black_box(&x);
}
// CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr }
// CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr }
// CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr }
// CHECK: %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
// CHECK: %struct.__tgt_kernel_arguments = type { i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, i64, i64, [3 x i32], [3 x i32], i32 }
// CHECK: @.offload_sizes._kernel_1 = private unnamed_addr constant [1 x i64] [i64 1024]
// CHECK: @.offload_maptypes._kernel_1 = private unnamed_addr constant [1 x i64] [i64 35]
// CHECK: @._kernel_1.region_id = internal unnamed_addr constant i8 0
// CHECK: @.offloading.entry_name._kernel_1 = internal unnamed_addr constant [10 x i8] c"_kernel_1\00", section ".llvm.rodata.offloading", align 1
// CHECK: @.offloading.entry._kernel_1 = internal constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @._kernel_1.region_id, ptr @.offloading.entry_name._kernel_1, i64 0, i64 0, ptr null }, section "llvm_offload_entries", align 8
// CHECK: @anon.{{.*}}.0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1
// CHECK: @anon.{{.*}}.1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @anon.{{.*}}.0 }, align 8
// CHECK: Function Attrs:
// CHECK-NEXT: define{{( dso_local)?}} void @main()
// CHECK: @.offload_sizes._kernel_1 = private unnamed_addr constant [1 x i64] [i64 1024]
// CHECK: @.offload_maptypes._kernel_1 = private unnamed_addr constant [1 x i64] [i64 35]
// CHECK: @._kernel_1.region_id = internal constant i8 0
// CHECK: @.offloading.entry_name._kernel_1 = internal unnamed_addr constant [10 x i8] c"_kernel_1\00", section ".llvm.rodata.offloading", align 1
// CHECK: @.offloading.entry._kernel_1 = internal constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @._kernel_1.region_id, ptr @.offloading.entry_name._kernel_1, i64 0, i64 0, ptr null }, section "llvm_offload_entries", align 8
// CHECK: Function Attrs: nounwind
// CHECK: declare i32 @__tgt_target_kernel(ptr, i64, i32, i32, ptr, ptr)
// CHECK: define{{( dso_local)?}} void @main()
// CHECK-NEXT: start:
// CHECK-NEXT: %0 = alloca [8 x i8], align 8
// CHECK-NEXT: %x = alloca [1024 x i8], align 16
// CHECK: call void @kernel_1(ptr noalias noundef nonnull align 4 dereferenceable(1024) %x)
// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %0)
// CHECK-NEXT: store ptr %x, ptr %0, align 8
// CHECK-NEXT: call void asm sideeffect "", "r,~{memory}"(ptr nonnull %0) #4, !srcloc !4
// CHECK-NEXT: call void asm sideeffect "", "r,~{memory}"(ptr nonnull %0)
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %0)
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1024, ptr nonnull %x)
// CHECK-NEXT: ret void
@ -92,9 +95,6 @@ fn main() {
// CHECK-NEXT: ret void
// CHECK-NEXT: }
// CHECK: Function Attrs: nounwind
// CHECK: declare i32 @__tgt_target_kernel(ptr, i64, i32, i32, ptr, ptr)
#[unsafe(no_mangle)]
#[inline(never)]
pub fn kernel_1(x: &mut [f32; 256]) {

View file

@ -0,0 +1,11 @@
//@ compile-flags:-Zunstable-options --remap-path-prefix={{src-base}}=
pub struct MyStruct {
field: u32,
}
impl MyStruct {
pub fn new() -> MyStruct {
MyStruct { field: 3 }
}
}

View file

@ -0,0 +1,19 @@
// This is a regression for `--remap-path-prefix` in an auxiliary dependency.
//
// We want to make sure that we can still have the "Source" links to the dependency
// even if its paths are remapped.
//
// See also rust-lang/rust#150100
//@ aux-build:remapped-paths.rs
//@ build-aux-docs
#![crate_name = "foo"]
extern crate remapped_paths;
//@ has foo/struct.MyStruct.html
//@ has - '//a[@href="../src/remapped_paths/remapped-paths.rs.html#3"]' 'Source'
//@ has - '//a[@href="../src/remapped_paths/remapped-paths.rs.html#8"]' 'Source'
pub use remapped_paths::MyStruct;

View file

@ -13,7 +13,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -41,7 +41,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -13,7 +13,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -52,7 +52,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -13,7 +13,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -52,7 +52,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -13,7 +13,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -52,7 +52,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -13,7 +13,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -41,7 +41,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -13,7 +13,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -52,7 +52,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -244,7 +244,7 @@ error: fn_abi_of(test_generic) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -328,7 +328,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -400,7 +400,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -479,7 +479,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -552,7 +552,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -629,7 +629,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -701,7 +701,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -779,7 +779,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -851,7 +851,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -962,7 +962,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -244,7 +244,7 @@ error: fn_abi_of(test_generic) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -328,7 +328,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -400,7 +400,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -479,7 +479,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -552,7 +552,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -629,7 +629,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -701,7 +701,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -779,7 +779,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -851,7 +851,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -962,7 +962,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -244,7 +244,7 @@ error: fn_abi_of(test_generic) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -328,7 +328,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -400,7 +400,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -479,7 +479,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -552,7 +552,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -629,7 +629,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -701,7 +701,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -779,7 +779,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -851,7 +851,7 @@ error: ABIs are not compatible
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -962,7 +962,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -24,7 +24,7 @@ error: fn_abi_of(extern_c) = FnAbi {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -65,7 +65,7 @@ error: fn_abi_of(extern_c) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -106,7 +106,7 @@ error: fn_abi_of(extern_rust) = FnAbi {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -165,7 +165,7 @@ error: fn_abi_of(extern_rust) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -13,7 +13,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -41,7 +41,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -141,12 +141,6 @@ LL | #[forbid(lint1, lint2, ...)]
LL | #[forbid(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++
error: malformed `thread_local` attribute input
--> $DIR/malformed-attrs.rs:210:1
|
LL | #[thread_local()]
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]`
error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/malformed-attrs.rs:105:1
|
@ -618,6 +612,15 @@ LL | #[non_exhaustive = 1]
| | didn't expect any arguments here
| help: must be of the form: `#[non_exhaustive]`
error[E0565]: malformed `thread_local` attribute input
--> $DIR/malformed-attrs.rs:210:1
|
LL | #[thread_local()]
| ^^^^^^^^^^^^^^--^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#[thread_local]`
error[E0565]: malformed `no_link` attribute input
--> $DIR/malformed-attrs.rs:214:1
|

View file

@ -13,7 +13,7 @@ error: fn_abi_of(take_va_list) = FnAbi {
},
fields: Arbitrary {
offsets: $OFFSETS,
memory_index: $MEMORY_INDEX,
in_memory_order: $MEMORY_INDEX,
},
largest_niche: None,
uninhabited: false,
@ -52,7 +52,7 @@ error: fn_abi_of(take_va_list) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -1,7 +1,7 @@
//@ check-fail
//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
//@ normalize-stderr: "valid_range: 0\.\.=\d+" -> "valid_range: 0..=$$MAX"
//@ normalize-stderr: "memory_index: \[[^\]]+\]" -> "memory_index: $$MEMORY_INDEX"
//@ normalize-stderr: "in_memory_order: \[[^\]]+\]" -> "in_memory_order: $$MEMORY_INDEX"
//@ normalize-stderr: "offsets: \[[^\]]+\]" -> "offsets: $$OFFSETS"
//@ revisions: x86_64 aarch64 win
//@ compile-flags: -O

View file

@ -20,7 +20,7 @@ error: fn_abi_of(take_va_list) = FnAbi {
),
fields: Arbitrary {
offsets: $OFFSETS,
memory_index: $MEMORY_INDEX,
in_memory_order: $MEMORY_INDEX,
},
largest_niche: None,
uninhabited: false,
@ -55,7 +55,7 @@ error: fn_abi_of(take_va_list) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -13,7 +13,7 @@ error: fn_abi_of(take_va_list) = FnAbi {
},
fields: Arbitrary {
offsets: $OFFSETS,
memory_index: $MEMORY_INDEX,
in_memory_order: $MEMORY_INDEX,
},
largest_niche: None,
uninhabited: false,
@ -52,7 +52,7 @@ error: fn_abi_of(take_va_list) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -91,7 +91,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi {
},
fields: Arbitrary {
offsets: $OFFSETS,
memory_index: $MEMORY_INDEX,
in_memory_order: $MEMORY_INDEX,
},
largest_niche: None,
uninhabited: false,
@ -130,7 +130,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -171,7 +171,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi {
},
fields: Arbitrary {
offsets: $OFFSETS,
memory_index: $MEMORY_INDEX,
in_memory_order: $MEMORY_INDEX,
},
largest_niche: None,
uninhabited: false,
@ -210,7 +210,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -16,7 +16,7 @@ error: layout_of(UnsignedAroundZero) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -52,7 +52,7 @@ error: layout_of(UnsignedAroundZero) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -73,7 +73,7 @@ error: layout_of(UnsignedAroundZero) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -94,7 +94,7 @@ error: layout_of(UnsignedAroundZero) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -134,7 +134,7 @@ error: layout_of(SignedAroundZero) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -170,7 +170,7 @@ error: layout_of(SignedAroundZero) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -191,7 +191,7 @@ error: layout_of(SignedAroundZero) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -212,7 +212,7 @@ error: layout_of(SignedAroundZero) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -16,7 +16,7 @@ error: layout_of(E) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -52,7 +52,7 @@ error: layout_of(E) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -77,7 +77,7 @@ error: layout_of(E) = Layout {
Size(4 bytes),
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
1,
2,
@ -130,7 +130,7 @@ error: layout_of(S) = Layout {
Size(8 bytes),
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
2,
1,
@ -200,7 +200,7 @@ error: layout_of(Result<i32, i32>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -251,7 +251,7 @@ error: layout_of(Result<i32, i32>) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -289,7 +289,7 @@ error: layout_of(Result<i32, i32>) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -16,7 +16,7 @@ error: layout_of(A) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -52,7 +52,7 @@ error: layout_of(A) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -92,7 +92,7 @@ error: layout_of(B) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -128,7 +128,7 @@ error: layout_of(B) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -168,7 +168,7 @@ error: layout_of(C) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -204,7 +204,7 @@ error: layout_of(C) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -244,7 +244,7 @@ error: layout_of(P) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -280,7 +280,7 @@ error: layout_of(P) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -320,7 +320,7 @@ error: layout_of(T) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -356,7 +356,7 @@ error: layout_of(T) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -22,7 +22,7 @@ error: layout_of(MissingPayloadField) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -72,7 +72,7 @@ error: layout_of(MissingPayloadField) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -95,7 +95,7 @@ error: layout_of(MissingPayloadField) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -142,7 +142,7 @@ error: layout_of(CommonPayloadField) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -193,7 +193,7 @@ error: layout_of(CommonPayloadField) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -231,7 +231,7 @@ error: layout_of(CommonPayloadField) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -279,7 +279,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -329,7 +329,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -366,7 +366,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -414,7 +414,7 @@ error: layout_of(NicheFirst) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -470,7 +470,7 @@ error: layout_of(NicheFirst) = Layout {
Size(0 bytes),
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
1,
],
@ -503,7 +503,7 @@ error: layout_of(NicheFirst) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -524,7 +524,7 @@ error: layout_of(NicheFirst) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -570,7 +570,7 @@ error: layout_of(NicheSecond) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -626,7 +626,7 @@ error: layout_of(NicheSecond) = Layout {
Size(1 bytes),
Size(0 bytes),
],
memory_index: [
in_memory_order: [
1,
0,
],
@ -659,7 +659,7 @@ error: layout_of(NicheSecond) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -680,7 +680,7 @@ error: layout_of(NicheSecond) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -10,7 +10,7 @@ error: layout_of(Aligned1) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -46,7 +46,7 @@ error: layout_of(Aligned1) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -69,7 +69,7 @@ error: layout_of(Aligned1) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -113,7 +113,7 @@ error: layout_of(Aligned2) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -149,7 +149,7 @@ error: layout_of(Aligned2) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -172,7 +172,7 @@ error: layout_of(Aligned2) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -16,7 +16,7 @@ error: layout_of(A) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -52,7 +52,7 @@ error: layout_of(A) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -92,7 +92,7 @@ error: layout_of(B) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -128,7 +128,7 @@ error: layout_of(B) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -168,7 +168,7 @@ error: layout_of(C) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -204,7 +204,7 @@ error: layout_of(C) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -244,7 +244,7 @@ error: layout_of(P) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -280,7 +280,7 @@ error: layout_of(P) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -320,7 +320,7 @@ error: layout_of(T) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -356,7 +356,7 @@ error: layout_of(T) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,

View file

@ -10,7 +10,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -48,7 +48,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -73,7 +73,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -118,7 +118,7 @@ error: layout_of(MultipleAlignments) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -156,7 +156,7 @@ error: layout_of(MultipleAlignments) = Layout {
offsets: [
Size(2 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -181,7 +181,7 @@ error: layout_of(MultipleAlignments) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -206,7 +206,7 @@ error: layout_of(MultipleAlignments) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -251,7 +251,7 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -289,7 +289,7 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -314,7 +314,7 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -359,7 +359,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -401,7 +401,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -426,7 +426,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -1,6 +1,5 @@
// Test where we fail to approximate due to demanding a postdom
// relationship between our upper bounds.
// Test that we can propagate multiple region errors for closure constraints
// where the longer region has multiple non-local lower bounds without any postdominating one.
//@ compile-flags:-Zverbose-internals
#![feature(rustc_attrs)]
@ -13,9 +12,8 @@ use std::cell::Cell;
// 'x: 'b
// 'c: 'y
//
// we have to prove that `'x: 'y`. We currently can only approximate
// via a postdominator -- hence we fail to choose between `'a` and
// `'b` here and report the error in the closure.
// we have to prove that `'x: 'y`. We find non-local lower bounds of 'x to be 'a and 'b and
// non-local upper bound of 'y to be 'c. So we propagate `'b: 'c` and `'a: 'c`.
fn establish_relationships<'a, 'b, 'c, F>(
_cell_a: Cell<&'a u32>,
_cell_b: Cell<&'b u32>,
@ -36,6 +34,8 @@ fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32)
#[rustc_regions]
fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
//~vv ERROR lifetime may not live long enough
//~v ERROR lifetime may not live long enough
establish_relationships(
cell_a,
cell_b,
@ -43,7 +43,7 @@ fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell
|_outlives1, _outlives2, _outlives3, x, y| {
// Only works if 'x: 'y:
let p = x.get();
demand_y(x, y, p) //~ ERROR
demand_y(x, y, p)
},
);
}

View file

@ -0,0 +1,79 @@
note: external requirements
--> $DIR/propagate-approximated-both-lower-bounds.rs:43:9
|
LL | |_outlives1, _outlives2, _outlives3, x, y| {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: supply::{closure#0} with closure args [
i16,
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'?2 &'^0 u32>, std::cell::Cell<&'^1 &'?3 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
(),
]
= note: late-bound region is '?7
= note: late-bound region is '?8
= note: late-bound region is '?4
= note: late-bound region is '?5
= note: late-bound region is '?6
= note: number of external vids: 7
= note: where '?2: '?3
= note: where '?1: '?3
note: no external requirements
--> $DIR/propagate-approximated-both-lower-bounds.rs:36:1
|
LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: supply
error: lifetime may not live long enough
--> $DIR/propagate-approximated-both-lower-bounds.rs:39:5
|
LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
| -- -- lifetime `'c` defined here
| |
| lifetime `'a` defined here
...
LL | / establish_relationships(
LL | | cell_a,
LL | | cell_b,
LL | | cell_c,
... |
LL | | },
LL | | );
| |_____^ argument requires that `'a` must outlive `'c`
|
= help: consider adding the following bound: `'a: 'c`
= note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant
= note: the struct `Cell<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/propagate-approximated-both-lower-bounds.rs:39:5
|
LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
| -- -- lifetime `'c` defined here
| |
| lifetime `'b` defined here
...
LL | / establish_relationships(
LL | | cell_a,
LL | | cell_b,
LL | | cell_c,
... |
LL | | },
LL | | );
| |_____^ argument requires that `'b` must outlive `'c`
|
= help: consider adding the following bound: `'b: 'c`
= note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant
= note: the struct `Cell<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: the following changes may resolve your lifetime errors
|
= help: add bound `'a: 'c`
= help: add bound `'b: 'c`
error: aborting due to 2 previous errors

View file

@ -1,42 +0,0 @@
note: no external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:43:9
|
LL | |_outlives1, _outlives2, _outlives3, x, y| {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: supply::{closure#0} with closure args [
i16,
for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'?2 &'^0 u32>, std::cell::Cell<&'^1 &'?3 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
(),
]
= note: late-bound region is '?7
= note: late-bound region is '?8
= note: late-bound region is '?4
= note: late-bound region is '?5
= note: late-bound region is '?6
error: lifetime may not live long enough
--> $DIR/propagate-approximated-fail-no-postdom.rs:46:13
|
LL | |_outlives1, _outlives2, _outlives3, x, y| {
| ---------- ---------- has type `Cell<&'2 &'?3 u32>`
| |
| has type `Cell<&'?1 &'1 u32>`
...
LL | demand_y(x, y, p)
| ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
= note: requirement occurs because of the type `Cell<&'?34 u32>`, which makes the generic argument `&'?34 u32` invariant
= note: the struct `Cell<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
note: no external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:38:1
|
LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: defining type: supply
error: aborting due to 1 previous error

View file

@ -0,0 +1,14 @@
//@ check-pass
// This checks that the compiler does not require that 'a: 'b. '_ has 'a and 'b as non-local
// upper bounds, but the compiler should not propagate 'a: 'b OR 'b: 'a when checking
// the closures. If it did, this would fail to compile, eventhough it's a valid program.
// PR #148329 explains this in detail.
struct MyTy<'x, 'a, 'b>(std::cell::Cell<(&'x &'a u8, &'x &'b u8)>);
fn wf<T>(_: T) {}
fn test<'a, 'b>() {
|_: &'a u8, x: MyTy<'_, 'a, 'b>| wf(x);
|x: MyTy<'_, 'a, 'b>, _: &'a u8| wf(x);
}
fn main(){}

View file

@ -0,0 +1,12 @@
//@ check-pass
// This test checks that the compiler propagates outlives requirements for both
// non-local lower bounds ['a, 'b] of '_, instead of conservatively finding a post-dominiting one
// from those 2.
struct MyTy<'a, 'b, 'x>(std::cell::Cell<(&'a &'x str, &'b &'x str)>);
fn wf<T>(_: T) {}
fn test<'a, 'b, 'x>() {
|x: MyTy<'a, 'b, '_>| wf(x);
}
fn main() {}

View file

@ -0,0 +1,26 @@
//@ check-pass
// This test checks that the compiler does not propagate 'd: 'c when propagating region errors
// for the closure argument. If it did, this would fail to compile, eventhough it's a valid program.
// It should only propagate 'd: 'b.
// PR #148329 explains this in detail.
#[derive(Clone, Copy)]
struct Inv<'a>(*mut &'a ());
impl<'a> Inv<'a> {
fn outlived_by<'b: 'a>(self, _: Inv<'b>) {}
}
struct OutlivedBy<'a, 'b: 'a>(Inv<'a>, Inv<'b>);
fn closure_arg<'b, 'c, 'd>(
_: impl for<'a> FnOnce(Inv<'a>, OutlivedBy<'a, 'b>, OutlivedBy<'a, 'c>, Inv<'d>),
) {
}
fn foo<'b, 'c, 'd: 'b>() {
closure_arg::<'b, 'c, 'd>(|a, b, c, d| {
a.outlived_by(b.1);
a.outlived_by(c.1);
b.1.outlived_by(d);
});
}
fn main() {}

View file

@ -16,7 +16,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -60,7 +60,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -108,7 +108,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -158,7 +158,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -195,7 +195,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -231,7 +231,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -270,7 +270,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
Size(8 bytes),
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
1,
],
@ -298,7 +298,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -16,7 +16,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -60,7 +60,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -108,7 +108,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -158,7 +158,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -195,7 +195,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -231,7 +231,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -270,7 +270,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
Size(8 bytes),
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
1,
],
@ -298,7 +298,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -16,7 +16,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -60,7 +60,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -108,7 +108,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -158,7 +158,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -195,7 +195,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -231,7 +231,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -270,7 +270,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
Size(8 bytes),
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
1,
],
@ -298,7 +298,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -16,7 +16,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -60,7 +60,7 @@ error: layout_of(Univariant) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -108,7 +108,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -158,7 +158,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -195,7 +195,7 @@ error: layout_of(TwoVariants) = Layout {
offsets: [
Size(4 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -231,7 +231,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -270,7 +270,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
Size(8 bytes),
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
1,
],
@ -298,7 +298,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
offsets: [
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -16,7 +16,7 @@ error: layout_of(UnivariantU8) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -60,7 +60,7 @@ error: layout_of(UnivariantU8) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -108,7 +108,7 @@ error: layout_of(TwoVariantsU8) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -158,7 +158,7 @@ error: layout_of(TwoVariantsU8) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -195,7 +195,7 @@ error: layout_of(TwoVariantsU8) = Layout {
offsets: [
Size(1 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -231,7 +231,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -270,7 +270,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
Size(8 bytes),
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
1,
],
@ -298,7 +298,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
offsets: [
Size(8 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -2,19 +2,19 @@
#![feature(thread_local)]
#[thread_local]
//~^ ERROR attribute should be applied to a static
//~^ ERROR `#[thread_local]` attribute cannot be used on constants
const A: u32 = 0;
#[thread_local]
//~^ ERROR attribute should be applied to a static
//~^ ERROR `#[thread_local]` attribute cannot be used on functions
fn main() {
#[thread_local] || {};
//~^ ERROR attribute should be applied to a static
//~^ ERROR `#[thread_local]` attribute cannot be used on closures
}
struct S {
#[thread_local]
//~^ ERROR attribute should be applied to a static
//~^ ERROR `#[thread_local]` attribute cannot be used on struct fields
a: String,
b: String,
}

View file

@ -1,38 +1,34 @@
error: attribute should be applied to a static
error: `#[thread_local]` attribute cannot be used on constants
--> $DIR/non-static.rs:4:1
|
LL | #[thread_local]
| ^^^^^^^^^^^^^^^
LL |
LL | const A: u32 = 0;
| ----------------- not a static
|
= help: `#[thread_local]` can be applied to foreign statics and statics
error: attribute should be applied to a static
error: `#[thread_local]` attribute cannot be used on functions
--> $DIR/non-static.rs:8:1
|
LL | #[thread_local]
| ^^^^^^^^^^^^^^^
LL |
LL | / fn main() {
LL | | #[thread_local] || {};
LL | |
LL | | }
| |_- not a static
LL | #[thread_local]
| ^^^^^^^^^^^^^^^
|
= help: `#[thread_local]` can be applied to foreign statics and statics
error: attribute should be applied to a static
error: `#[thread_local]` attribute cannot be used on closures
--> $DIR/non-static.rs:11:5
|
LL | #[thread_local] || {};
| ^^^^^^^^^^^^^^^ ----- not a static
| ^^^^^^^^^^^^^^^
|
= help: `#[thread_local]` can be applied to foreign statics and statics
error: attribute should be applied to a static
error: `#[thread_local]` attribute cannot be used on struct fields
--> $DIR/non-static.rs:16:5
|
LL | #[thread_local]
| ^^^^^^^^^^^^^^^
LL |
LL | a: String,
| --------- not a static
|
= help: `#[thread_local]` can be applied to foreign statics and statics
error: aborting due to 4 previous errors

View file

@ -17,7 +17,7 @@ error: layout_of((*const T) is !null) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -64,7 +64,7 @@ error: layout_of(Option<(*const ()) is !null>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -96,7 +96,7 @@ error: layout_of(Option<(*const ()) is !null>) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -126,7 +126,7 @@ error: layout_of(Option<(*const ()) is !null>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -186,7 +186,7 @@ error: layout_of((*const [u8]) is !null) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -57,7 +57,7 @@ error: layout_of((i8) is (i8::MIN..=-1 | 1..)) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -102,7 +102,7 @@ error: layout_of((i8) is (i8::MIN..=-2 | 0..)) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},

View file

@ -16,7 +16,7 @@ error: layout_of(NonZero<u32>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -61,7 +61,7 @@ error: layout_of((u32) is 1..) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -106,7 +106,7 @@ error: layout_of(Option<(u32) is 1..>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -137,7 +137,7 @@ error: layout_of(Option<(u32) is 1..>) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -166,7 +166,7 @@ error: layout_of(Option<(u32) is 1..>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -217,7 +217,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -248,7 +248,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
},
fields: Arbitrary {
offsets: [],
memory_index: [],
in_memory_order: [],
},
largest_niche: None,
uninhabited: false,
@ -277,7 +277,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -328,7 +328,7 @@ error: layout_of(NonZeroU32New) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -401,7 +401,7 @@ error: layout_of((i8) is -10..=10) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},
@ -446,7 +446,7 @@ error: layout_of((i8) is i8::MIN..=0) = Layout {
offsets: [
Size(0 bytes),
],
memory_index: [
in_memory_order: [
0,
],
},