Auto merge of #146409 - matthiaskrgr:rollup-thju381, r=matthiaskrgr

Rollup of 5 pull requests

Successful merges:

 - rust-lang/rust#144765 (inclusive `Range`s: change `end` to `last`)
 - rust-lang/rust#146178 (Implement `#[rustc_align_static(N)]` on `static`s)
 - rust-lang/rust#146368 (CI: rfl: move job forward to Linux v6.17-rc5 to remove temporary commits)
 - rust-lang/rust#146378 (Update wasm-component-ld to 0.5.17)
 - rust-lang/rust#146391 (Trim paths less in MIR dumping)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-09-10 15:09:18 +00:00
commit 565a9ca63e
49 changed files with 530 additions and 97 deletions

View file

@ -5984,9 +5984,9 @@ dependencies = [
[[package]]
name = "wasm-component-ld"
version = "0.5.16"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14cd35d6cae91109a0ffd207b573cf3c741cab7e921dd376ea7aaf2c52a3408c"
checksum = "1c9208f87cac2332fd80dcf36d54e9163d3446e28301e0c6e424984425738984"
dependencies = [
"anyhow",
"clap",
@ -5994,9 +5994,9 @@ dependencies = [
"libc",
"tempfile",
"wasi-preview1-component-adapter-provider",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
"wat",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
"winsplit",
"wit-component",
"wit-parser",
@ -6021,24 +6021,24 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efe92d1321afa53ffc88a57c497bb7330c3cf84c98ffdba4a4caf6a0684fad3c"
checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c"
dependencies = [
"leb128fmt",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
]
[[package]]
name = "wasm-metadata"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cc0b0a0c4f35ca6efa7a797671372915d4e9659dba2d59edc6fafc931d19997"
checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder 0.237.0",
"wasmparser 0.237.0",
"wasm-encoder 0.239.0",
"wasmparser 0.239.0",
]
[[package]]
@ -6063,9 +6063,9 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250"
checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0"
dependencies = [
"bitflags",
"hashbrown",
@ -6076,22 +6076,22 @@ dependencies = [
[[package]]
name = "wast"
version = "237.0.0"
version = "239.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcf66f545acbd55082485cb9a6daab54579cb8628a027162253e8e9f5963c767"
checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width 0.2.1",
"wasm-encoder 0.237.0",
"wasm-encoder 0.239.0",
]
[[package]]
name = "wat"
version = "1.237.0"
version = "1.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27975186f549e4b8d6878b627be732863883c72f7bf4dcf8f96e5f8242f73da9"
checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75"
dependencies = [
"wast",
]
@ -6580,9 +6580,9 @@ dependencies = [
[[package]]
name = "wit-component"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb7674f76c10e82fe00b256a9d4ffb2b8d037d42ab8e9a83ebb3be35c9d0bf6"
checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136"
dependencies = [
"anyhow",
"bitflags",
@ -6591,17 +6591,17 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"wasm-encoder 0.237.0",
"wasm-encoder 0.239.0",
"wasm-metadata",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce2596a5bc7c24cc965b56ad6ff9e32394c4e401764f89620a888519c6e849ab"
checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d"
dependencies = [
"anyhow",
"id-arena",
@ -6612,7 +6612,7 @@ dependencies = [
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
]
[[package]]

View file

@ -1536,7 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::LangItem::Range
}
}
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
(None, Some(..), Closed) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeToInclusiveCopy
} else {
hir::LangItem::RangeToInclusive
}
}
(Some(e1), Some(e2), Closed) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeInclusiveCopy
@ -1560,13 +1566,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
let fields = self.arena.alloc_from_iter(
e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
|(s, e)| {
e1.iter()
.map(|e| (sym::start, e))
.chain(e2.iter().map(|e| {
(
if matches!(
lang_item,
hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy
) {
sym::last
} else {
sym::end
},
e,
)
}))
.map(|(s, e)| {
let expr = self.lower_expr(e);
let ident = Ident::new(s, self.lower_span(e.span));
self.expr_field(ident, expr, e.span)
},
),
}),
);
hir::ExprKind::Struct(

View file

@ -218,6 +218,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
sym::rustc_std_internal_symbol,
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
sym::rustc_align,
sym::rustc_align_static,
// obviously compatible with self
sym::naked,
// documentation

View file

@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
Some(AttributeKind::Align { align, span })
}
}
#[derive(Default)]
pub(crate) struct AlignStaticParser(AlignParser);
impl AlignStaticParser {
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
fn parse<'c, S: Stage>(
&mut self,
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) {
self.0.parse(cx, args)
}
}
impl<S: Stage> AttributeParser<S> for AlignStaticParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
let (align, span) = self.0.0?;
Some(AttributeKind::Align { align, span })
}
}

View file

@ -50,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
};
use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, ReprParser};
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
RustcObjectLifetimeDefaultParser,
@ -152,6 +152,7 @@ attribute_parsers!(
pub(crate) static ATTRIBUTE_PARSERS = [
// tidy-alphabetical-start
AlignParser,
AlignStaticParser,
BodyStabilityParser,
ConfusablesParser,
ConstStabilityParser,

View file

@ -81,6 +81,8 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
if global.to_rvalue().get_type() != val_llty {
global.to_rvalue().set_type(val_llty);
}
// NOTE: Alignment from attributes has already been applied to the allocation.
set_global_alignment(self, global, alloc.align);
global.global_set_initializer_rvalue(value);

View file

@ -452,6 +452,8 @@ impl<'ll> CodegenCx<'ll, '_> {
self.statics_to_rauw.borrow_mut().push((g, new_g));
new_g
};
// NOTE: Alignment from attributes has already been applied to the allocation.
set_global_alignment(self, g, alloc.align);
llvm::set_initializer(g, v);

View file

@ -953,6 +953,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// # Global allocations
if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
// NOTE: `static` alignment from attributes has already been applied to the allocation.
let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env);
let mutbl = global_alloc.mutability(*self.tcx, self.typing_env);
let kind = match global_alloc {

View file

@ -1,6 +1,6 @@
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer};
use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt};
use tracing::debug;
@ -38,7 +38,14 @@ pub(crate) fn create_static_alloc<'tcx>(
static_def_id: LocalDefId,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit, ())?;
// Inherit size and align from the `GlobalAlloc::Static` so we can avoid duplicating
// the alignment attribute logic.
let (size, align) =
GlobalAlloc::Static(static_def_id.into()).size_and_align(*ecx.tcx, ecx.typing_env);
assert_eq!(size, layout.size);
assert!(align >= layout.align.abi);
let alloc = Allocation::try_new(size, align, AllocInit::Uninit, ())?;
let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into());
assert_eq!(ecx.machine.static_root_ids, None);
ecx.machine.static_root_ids = Some((alloc_id, static_def_id));

View file

@ -621,6 +621,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)),
ungated!(
unsafe(Edition2024) export_name, Normal,
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),

View file

@ -632,6 +632,8 @@ declare_features! (
(unstable, simd_ffi, "1.0.0", Some(27731)),
/// Allows specialization of implementations (RFC 1210).
(incomplete, specialization, "1.7.0", Some(31844)),
/// Allows using `#[rustc_align_static(...)]` on static items.
(unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)),
/// Allows attributes on expressions and non-item statements.
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
/// Allows lints part of the strict provenance effort.

View file

@ -2614,6 +2614,18 @@ impl Expr<'_> {
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
[val1],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
[val2],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeFrom, _),
@ -2705,7 +2717,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
| LangItem::RangeToInclusive
| LangItem::RangeCopy
| LangItem::RangeFromCopy
| LangItem::RangeInclusiveCopy,
| LangItem::RangeInclusiveCopy
| LangItem::RangeToInclusiveCopy,
..
)
),

View file

@ -422,6 +422,7 @@ language_item_table! {
RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None;
RangeCopy, sym::RangeCopy, range_copy_struct, Target::Struct, GenericRequirement::None;
RangeInclusiveCopy, sym::RangeInclusiveCopy, range_inclusive_copy_struct, Target::Struct, GenericRequirement::None;
RangeToInclusiveCopy, sym::RangeToInclusiveCopy, range_to_inclusive_copy_struct, Target::Struct, GenericRequirement::None;
String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;

View file

@ -130,7 +130,22 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> {
impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> {
type Output = core::range::RangeInclusive<usize>;
#[inline]
#[cfg(bootstrap)]
fn into_slice_idx(self) -> Self::Output {
core::range::RangeInclusive { start: self.start.index(), end: self.end.index() }
}
#[inline]
#[cfg(not(bootstrap))]
fn into_slice_idx(self) -> Self::Output {
core::range::RangeInclusive { start: self.start.index(), last: self.last.index() }
}
}
#[cfg(all(feature = "nightly", not(bootstrap)))]
impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeToInclusive<I> {
type Output = core::range::RangeToInclusive<usize>;
#[inline]
fn into_slice_idx(self) -> Self::Output {
core::range::RangeToInclusive { last: self.last.index() }
}
}

View file

@ -386,7 +386,16 @@ impl<'tcx> GlobalAlloc<'tcx> {
.expect("statics should not have generic parameters");
let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
assert!(layout.is_sized());
(layout.size, layout.align.abi)
// Take over-alignment from attributes into account.
let align = match tcx.codegen_fn_attrs(def_id).alignment {
Some(align_from_attribute) => {
Ord::max(align_from_attribute, layout.align.abi)
}
None => layout.align.abi,
};
(layout.size, align)
}
}
GlobalAlloc::Memory(alloc) => {

View file

@ -78,8 +78,9 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, pass_name: &'static str, body: &Body<'tcx>) -> Option<Self> {
let dump_enabled = if let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir {
// see notes on #41697 below
let node_path =
ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
let node_path = ty::print::with_no_trimmed_paths!(
ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()))
);
filters.split('|').any(|or_filter| {
or_filter.split('&').all(|and_filter| {
let and_filter_trimmed = and_filter.trim();
@ -173,9 +174,10 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> {
// trigger `type_of`, and this can run while we are already attempting to evaluate `type_of`.
pub fn dump_mir_to_writer(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> {
// see notes on #41697 above
let def_path = ty::print::with_forced_impl_filename_line!(
self.tcx().def_path_str(body.source.def_id())
);
let def_path =
ty::print::with_no_trimmed_paths!(ty::print::with_forced_impl_filename_line!(
self.tcx().def_path_str(body.source.def_id())
));
// ignore-tidy-odd-backticks the literal below is fine
write!(w, "// MIR for `{def_path}")?;
match body.source.promoted {

View file

@ -501,6 +501,10 @@ passes_repr_align_should_be_align =
`#[repr(align(...))]` is not supported on {$item}
.help = use `#[rustc_align(...)]` instead
passes_repr_align_should_be_align_static =
`#[repr(align(...))]` is not supported on {$item}
.help = use `#[rustc_align_static(...)]` instead
passes_repr_conflicting =
conflicting representation hints

View file

@ -1606,12 +1606,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
ReprAttr::ReprAlign(align) => {
match target {
Target::Struct | Target::Union | Target::Enum => {}
Target::Fn | Target::Method(_) => {
Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => {
self.dcx().emit_err(errors::ReprAlignShouldBeAlign {
span: *repr_span,
item: target.plural_name(),
});
}
Target::Static if self.tcx.features().static_align() => {
self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic {
span: *repr_span,
item: target.plural_name(),
});
}
_ => {
self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
hint_span: *repr_span,

View file

@ -1609,6 +1609,15 @@ pub(crate) struct ReprAlignShouldBeAlign {
pub item: &'static str,
}
#[derive(Diagnostic)]
#[diag(passes_repr_align_should_be_align_static)]
pub(crate) struct ReprAlignShouldBeAlignStatic {
#[primary_span]
#[help]
pub span: Span,
pub item: &'static str,
}
#[derive(Diagnostic)]
#[diag(passes_custom_mir_phase_requires_dialect)]
pub(crate) struct CustomMirPhaseRequiresDialect {

View file

@ -326,6 +326,7 @@ symbols! {
RangeSub,
RangeTo,
RangeToInclusive,
RangeToInclusiveCopy,
Rc,
RcWeak,
Ready,
@ -1280,6 +1281,7 @@ symbols! {
lang,
lang_items,
large_assignments,
last,
lateout,
lazy_normalization_consts,
lazy_type_alias,
@ -1846,6 +1848,7 @@ symbols! {
rustc_abi,
// FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity
rustc_align,
rustc_align_static,
rustc_allocator,
rustc_allocator_zeroed,
rustc_allocator_zeroed_variant,
@ -2097,6 +2100,7 @@ symbols! {
staged_api,
start,
state,
static_align,
static_in_const,
static_nobundle,
static_recursion,

View file

@ -31,9 +31,7 @@ pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive};
#[doc(inline)]
pub use crate::iter::Step;
#[doc(inline)]
pub use crate::ops::{
Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive,
};
pub use crate::ops::{Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo};
/// A (half-open) range bounded inclusively below and exclusively above
/// (`start..end` in a future edition).
@ -209,20 +207,20 @@ impl<T> const From<legacy::Range<T>> for Range<T> {
}
}
/// A range bounded inclusively below and above (`start..=end`).
/// A range bounded inclusively below and above (`start..=last`).
///
/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
/// and `x <= end`. It is empty unless `start <= end`.
/// The `RangeInclusive` `start..=last` contains all values with `x >= start`
/// and `x <= last`. It is empty unless `start <= last`.
///
/// # Examples
///
/// The `start..=end` syntax is a `RangeInclusive`:
/// The `start..=last` syntax is a `RangeInclusive`:
///
/// ```
/// #![feature(new_range_api)]
/// use core::range::RangeInclusive;
///
/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 });
/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, last: 5 });
/// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum());
/// ```
#[lang = "RangeInclusiveCopy"]
@ -234,7 +232,7 @@ pub struct RangeInclusive<Idx> {
pub start: Idx,
/// The upper bound of the range (inclusive).
#[unstable(feature = "new_range_api", issue = "125687")]
pub end: Idx,
pub last: Idx,
}
#[unstable(feature = "new_range_api", issue = "125687")]
@ -242,7 +240,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.start.fmt(fmt)?;
write!(fmt, "..=")?;
self.end.fmt(fmt)?;
self.last.fmt(fmt)?;
Ok(())
}
}
@ -306,7 +304,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
#[unstable(feature = "new_range_api", issue = "125687")]
#[inline]
pub fn is_empty(&self) -> bool {
!(self.start <= self.end)
!(self.start <= self.last)
}
}
@ -335,10 +333,10 @@ impl<Idx: Step> RangeInclusive<Idx> {
impl RangeInclusive<usize> {
/// Converts to an exclusive `Range` for `SliceIndex` implementations.
/// The caller is responsible for dealing with `end == usize::MAX`.
/// The caller is responsible for dealing with `last == usize::MAX`.
#[inline]
pub(crate) const fn into_slice_range(self) -> Range<usize> {
Range { start: self.start, end: self.end + 1 }
Range { start: self.start, end: self.last + 1 }
}
}
@ -348,7 +346,7 @@ impl<T> RangeBounds<T> for RangeInclusive<T> {
Included(&self.start)
}
fn end_bound(&self) -> Bound<&T> {
Included(&self.end)
Included(&self.last)
}
}
@ -364,7 +362,7 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> {
Included(self.start)
}
fn end_bound(&self) -> Bound<&T> {
Included(self.end)
Included(self.last)
}
}
@ -372,7 +370,7 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> {
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> IntoBounds<T> for RangeInclusive<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Included(self.start), Included(self.end))
(Included(self.start), Included(self.last))
}
}
@ -381,7 +379,7 @@ impl<T> IntoBounds<T> for RangeInclusive<T> {
impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
#[inline]
fn from(value: RangeInclusive<T>) -> Self {
Self::new(value.start, value.end)
Self::new(value.start, value.last)
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
@ -394,8 +392,8 @@ impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
"attempted to convert from an exhausted `legacy::RangeInclusive` (unspecified behavior)"
);
let (start, end) = value.into_inner();
RangeInclusive { start, end }
let (start, last) = value.into_inner();
RangeInclusive { start, last }
}
}
@ -544,3 +542,107 @@ impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> {
Self { start: value.start }
}
}
/// A range only bounded inclusively above (`..=last`).
///
/// The `RangeToInclusive` `..=last` contains all values with `x <= last`.
/// It cannot serve as an [`Iterator`] because it doesn't have a starting point.
///
/// # Examples
///
/// The `..=last` syntax is a `RangeToInclusive`:
///
/// ```
/// #![feature(new_range_api)]
/// #![feature(new_range)]
/// assert_eq!((..=5), std::range::RangeToInclusive{ last: 5 });
/// ```
///
/// It does not have an [`IntoIterator`] implementation, so you can't use it in a
/// `for` loop directly. This won't compile:
///
/// ```compile_fail,E0277
/// // error[E0277]: the trait bound `std::range::RangeToInclusive<{integer}>:
/// // std::iter::Iterator` is not satisfied
/// for i in ..=5 {
/// // ...
/// }
/// ```
///
/// When used as a [slicing index], `RangeToInclusive` produces a slice of all
/// array elements up to and including the index indicated by `last`.
///
/// ```
/// let arr = [0, 1, 2, 3, 4];
/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]);
/// assert_eq!(arr[ .. 3], [0, 1, 2 ]);
/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); // This is a `RangeToInclusive`
/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]);
/// assert_eq!(arr[1.. 3], [ 1, 2 ]);
/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]);
/// ```
///
/// [slicing index]: crate::slice::SliceIndex
#[lang = "RangeToInclusiveCopy"]
#[doc(alias = "..=")]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[unstable(feature = "new_range_api", issue = "125687")]
pub struct RangeToInclusive<Idx> {
/// The upper bound of the range (inclusive)
#[unstable(feature = "new_range_api", issue = "125687")]
pub last: Idx,
}
#[unstable(feature = "new_range_api", issue = "125687")]
impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "..=")?;
self.last.fmt(fmt)?;
Ok(())
}
}
impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// # Examples
///
/// ```
/// assert!( (..=5).contains(&-1_000_000_000));
/// assert!( (..=5).contains(&5));
/// assert!(!(..=5).contains(&6));
///
/// assert!( (..=1.0).contains(&1.0));
/// assert!(!(..=1.0).contains(&f32::NAN));
/// assert!(!(..=f32::NAN).contains(&0.5));
/// ```
#[inline]
#[unstable(feature = "new_range_api", issue = "125687")]
pub fn contains<U>(&self, item: &U) -> bool
where
Idx: PartialOrd<U>,
U: ?Sized + PartialOrd<Idx>,
{
<Self as RangeBounds<Idx>>::contains(self, item)
}
}
// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>>
// because underflow would be possible with (..0).into()
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> RangeBounds<T> for RangeToInclusive<T> {
fn start_bound(&self) -> Bound<&T> {
Unbounded
}
fn end_bound(&self) -> Bound<&T> {
Included(&self.last)
}
}
#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for RangeToInclusive<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Unbounded, Included(self.last))
}
}

View file

@ -164,7 +164,7 @@ impl<A: Step> IterRangeInclusive<A> {
return None;
}
Some(RangeInclusive { start: self.0.start, end: self.0.end })
Some(RangeInclusive { start: self.0.start, last: self.0.end })
}
}

View file

@ -1,10 +1,10 @@
//! # Legacy range types
//!
//! The types within this module will be replaced by the types
//! [`Range`], [`RangeInclusive`], and [`RangeFrom`] in the parent
//! [`Range`], [`RangeInclusive`], [`RangeToInclusive`], and [`RangeFrom`] in the parent
//! module, [`core::range`].
//!
//! The types here are equivalent to those in [`core::ops`].
#[doc(inline)]
pub use crate::ops::{Range, RangeFrom, RangeInclusive};
pub use crate::ops::{Range, RangeFrom, RangeInclusive, RangeToInclusive};

View file

@ -129,6 +129,8 @@ mod private_slice_index {
#[unstable(feature = "new_range_api", issue = "125687")]
impl Sealed for range::RangeInclusive<usize> {}
#[unstable(feature = "new_range_api", issue = "125687")]
impl Sealed for range::RangeToInclusive<usize> {}
#[unstable(feature = "new_range_api", issue = "125687")]
impl Sealed for range::RangeFrom<usize> {}
impl Sealed for ops::IndexRange {}
@ -788,6 +790,45 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
}
}
/// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
#[stable(feature = "inclusive_range", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
unsafe impl<T> const SliceIndex<[T]> for range::RangeToInclusive<usize> {
type Output = [T];
#[inline]
fn get(self, slice: &[T]) -> Option<&[T]> {
(0..=self.last).get(slice)
}
#[inline]
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
(0..=self.last).get_mut(slice)
}
#[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
unsafe { (0..=self.last).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
unsafe { (0..=self.last).get_unchecked_mut(slice) }
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
(0..=self.last).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
(0..=self.last).index_mut(slice)
}
}
/// Performs bounds checking of a range.
///
/// This method is similar to [`Index::index`] for slices, but it returns a

View file

@ -677,11 +677,11 @@ unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
if self.end == usize::MAX { None } else { self.into_slice_range().get(slice) }
if self.last == usize::MAX { None } else { self.into_slice_range().get(slice) }
}
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
if self.end == usize::MAX { None } else { self.into_slice_range().get_mut(slice) }
if self.last == usize::MAX { None } else { self.into_slice_range().get_mut(slice) }
}
#[inline]
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
@ -695,14 +695,14 @@ unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> {
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
if self.end == usize::MAX {
if self.last == usize::MAX {
str_index_overflow_fail();
}
self.into_slice_range().index(slice)
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
if self.end == usize::MAX {
if self.last == usize::MAX {
str_index_overflow_fail();
}
self.into_slice_range().index_mut(slice)

View file

@ -2,9 +2,7 @@
set -euo pipefail
# https://github.com/rust-lang/rust/pull/144443
# https://github.com/rust-lang/rust/pull/145928
LINUX_VERSION=8851e27d2cb947ea8bbbe8e812068f7bf5cbd00b
LINUX_VERSION=v6.17-rc5
# Build rustc, rustdoc, cargo, clippy-driver and rustfmt
../x.py build --stage 2 library rustdoc clippy rustfmt

View file

@ -194,7 +194,6 @@ generate! {
itertools,
join,
kw,
last,
lazy_static,
lint_vec,
ln,

View file

@ -0,0 +1,14 @@
#![feature(static_align)]
// When a static uses `align(N)`, its address should be a multiple of `N`.
#[rustc_align_static(256)]
static FOO: u64 = 0;
#[rustc_align_static(512)]
static BAR: u64 = 0;
fn main() {
assert!(core::ptr::from_ref(&FOO).addr().is_multiple_of(256));
assert!(core::ptr::from_ref(&BAR).addr().is_multiple_of(512));
}

View file

@ -10,4 +10,4 @@ name = "wasm-component-ld"
path = "src/main.rs"
[dependencies]
wasm-component-ld = "0.5.16"
wasm-component-ld = "0.5.17"

View file

@ -0,0 +1,31 @@
//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
#![crate_type = "lib"]
#![feature(static_align)]
// CHECK: @STATIC_ALIGN =
// CHECK-SAME: align 16
#[no_mangle]
#[rustc_align_static(16)]
pub static STATIC_ALIGN: u64 = 0;
// CHECK: @ALIGN_SPECIFIED_TWICE_1 =
// CHECK-SAME: align 64
#[no_mangle]
#[rustc_align_static(32)]
#[rustc_align_static(64)]
pub static ALIGN_SPECIFIED_TWICE_1: u64 = 0;
// CHECK: @ALIGN_SPECIFIED_TWICE_2 =
// CHECK-SAME: align 128
#[no_mangle]
#[rustc_align_static(128)]
#[rustc_align_static(32)]
pub static ALIGN_SPECIFIED_TWICE_2: u64 = 0;
// CHECK: @ALIGN_SPECIFIED_TWICE_3 =
// CHECK-SAME: align 256
#[no_mangle]
#[rustc_align_static(32)]
#[rustc_align_static(256)]
pub static ALIGN_SPECIFIED_TWICE_3: u64 = 0;

View file

@ -1,4 +1,4 @@
// MIR for `drop_in_place` after SimplifyCfg-make_shim
// MIR for `std::ptr::drop_in_place` after SimplifyCfg-make_shim
fn drop_in_place(_1: *mut Test) -> () {
let mut _0: ();

View file

@ -1,4 +1,4 @@
// MIR for `drop_in_place` after SimplifyCfg-make_shim
// MIR for `std::ptr::drop_in_place` after SimplifyCfg-make_shim
fn drop_in_place(_1: *mut Test) -> () {
let mut _0: ();

View file

@ -1,4 +1,4 @@
// MIR for `drop_in_place` before AddMovesForPackedDrops
// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
fn drop_in_place(_1: *mut [String; 42]) -> () {
let mut _0: ();

View file

@ -1,4 +1,4 @@
// MIR for `drop_in_place` before AddMovesForPackedDrops
// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
fn drop_in_place(_1: *mut [String]) -> () {
let mut _0: ();

View file

@ -1,4 +1,4 @@
// MIR for `drop_in_place` before AddMovesForPackedDrops
// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
fn drop_in_place(_1: *mut Vec<i32>) -> () {
let mut _0: ();

View file

@ -0,0 +1,17 @@
#![feature(static_align)]
#![crate_type = "lib"]
#[rustc_align_static = 16] //~ ERROR malformed `rustc_align_static` attribute input
static S1: () = ();
#[rustc_align_static("hello")] //~ ERROR invalid alignment value: not an unsuffixed integer
static S2: () = ();
#[rustc_align_static(0)] //~ ERROR invalid alignment value: not a power of two
static S3: () = ();
#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on static
static S4: () = ();
#[rustc_align_static(16)] //~ ERROR `#[rustc_align_static]` attribute cannot be used on structs
struct Struct1;

View file

@ -0,0 +1,45 @@
error[E0539]: malformed `rustc_align_static` attribute input
--> $DIR/malformed-static-align.rs:4:1
|
LL | #[rustc_align_static = 16]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected this to be a list
| help: must be of the form: `#[rustc_align_static(<alignment in bytes>)]`
error[E0589]: invalid alignment value: not an unsuffixed integer
--> $DIR/malformed-static-align.rs:7:22
|
LL | #[rustc_align_static("hello")]
| ^^^^^^^
error[E0589]: invalid alignment value: not a power of two
--> $DIR/malformed-static-align.rs:10:22
|
LL | #[rustc_align_static(0)]
| ^
error: `#[rustc_align_static]` attribute cannot be used on structs
--> $DIR/malformed-static-align.rs:16:1
|
LL | #[rustc_align_static(16)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[rustc_align_static]` can be applied to statics and foreign statics
error: `#[repr(align(...))]` is not supported on statics
--> $DIR/malformed-static-align.rs:13:8
|
LL | #[repr(align(16))]
| ^^^^^^^^^
|
help: use `#[rustc_align_static(...)]` instead
--> $DIR/malformed-static-align.rs:13:8
|
LL | #[repr(align(16))]
| ^^^^^^^^^
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0539, E0589.
For more information about an error, try `rustc --explain E0539`.

View file

@ -28,7 +28,7 @@ error[E0741]: `RangeTo<usize>` must implement `ConstParamTy` to be used as the t
LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0741]: `RangeToInclusive<usize>` must implement `ConstParamTy` to be used as the type of a const generic parameter
error[E0741]: `std::ops::RangeToInclusive<usize>` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/const-generics-range.rs:34:35
|
LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;

View file

@ -58,7 +58,7 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
LL + #![feature(adt_const_params)]
|
error: `RangeToInclusive<usize>` is forbidden as the type of a const generic parameter
error: `std::ops::RangeToInclusive<usize>` is forbidden as the type of a const generic parameter
--> $DIR/const-generics-range.rs:34:35
|
LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;

View file

@ -7,32 +7,32 @@
// `Range` should be usable within const generics:
struct _Range<const R: std::ops::Range<usize>>;
//[min]~^ ERROR `std::ops::Range<usize>` is forbidden
const RANGE : _Range<{ 0 .. 1000 }> = _Range;
const RANGE: _Range<{ 0..1000 }> = _Range;
// `RangeFrom` should be usable within const generics:
struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
//[min]~^ ERROR `std::ops::RangeFrom<usize>` is forbidden
const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom;
const RANGE_FROM: _RangeFrom<{ 0.. }> = _RangeFrom;
// `RangeFull` should be usable within const generics:
struct _RangeFull<const R: std::ops::RangeFull>;
//[min]~^ ERROR `RangeFull` is forbidden
const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull;
const RANGE_FULL: _RangeFull<{ .. }> = _RangeFull;
// Regression test for #70155
// `RangeInclusive` should be usable within const generics:
struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
//[min]~^ ERROR `std::ops::RangeInclusive<usize>` is forbidden
const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive;
const RANGE_INCLUSIVE: _RangeInclusive<{ 0..=999 }> = _RangeInclusive;
// `RangeTo` should be usable within const generics:
struct _RangeTo<const R: std::ops::RangeTo<usize>>;
//[min]~^ ERROR `RangeTo<usize>` is forbidden
const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo;
const RANGE_TO: _RangeTo<{ ..1000 }> = _RangeTo;
// `RangeToInclusive` should be usable within const generics:
struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
//[min]~^ ERROR `RangeToInclusive<usize>` is forbidden
const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive;
//[min]~^ ERROR `std::ops::RangeToInclusive<usize>` is forbidden
const RANGE_TO_INCLUSIVE: _RangeToInclusive<{ ..=999 }> = _RangeToInclusive;
pub fn main() {}

View file

@ -0,0 +1,11 @@
#![crate_type = "lib"]
#[rustc_align_static(16)]
//~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature
static REQUIRES_ALIGNMENT: u64 = 0;
extern "C" {
#[rustc_align_static(16)]
//~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature
static FOREIGN_STATIC: u32;
}

View file

@ -0,0 +1,23 @@
error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature
--> $DIR/feature-gate-static_align.rs:3:1
|
LL | #[rustc_align_static(16)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information
= help: add `#![feature(static_align)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature
--> $DIR/feature-gate-static_align.rs:8:5
|
LL | #[rustc_align_static(16)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information
= help: add `#![feature(static_align)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -8,15 +8,15 @@ LL | for _ in ..10 {}
= note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end`
= note: required for `RangeTo<{integer}>` to implement `IntoIterator`
error[E0277]: `RangeToInclusive<{integer}>` is not an iterator
error[E0277]: `std::ops::RangeToInclusive<{integer}>` is not an iterator
--> $DIR/ranges.rs:4:14
|
LL | for _ in ..=10 {}
| ^^^^^ if you meant to iterate until a value (including it), add a starting value
|
= help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>`
= help: the trait `Iterator` is not implemented for `std::ops::RangeToInclusive<{integer}>`
= note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end`
= note: required for `RangeToInclusive<{integer}>` to implement `IntoIterator`
= note: required for `std::ops::RangeToInclusive<{integer}>` to implement `IntoIterator`
error: aborting due to 2 previous errors

View file

@ -6,20 +6,20 @@ fn main() {
// Unchanged
let a: core::range::RangeFull = ..;
let b: core::range::RangeTo<u8> = ..2;
let c: core::range::RangeToInclusive<u8> = ..=3;
let _: core::ops::RangeFull = a;
let _: core::ops::RangeTo<u8> = b;
let _: core::ops::RangeToInclusive<u8> = c;
// Changed
let a: core::range::legacy::RangeFrom<u8> = 1..;
let b: core::range::legacy::Range<u8> = 2..3;
let c: core::range::legacy::RangeInclusive<u8> = 4..=5;
let d: core::range::legacy::RangeToInclusive<u8> = ..=3;
let a: core::ops::RangeFrom<u8> = a;
let b: core::ops::Range<u8> = b;
let c: core::ops::RangeInclusive<u8> = c;
let d: core::ops::RangeToInclusive<u8> = d;
let _: core::ops::RangeFrom<u8> = a.into_iter();
let _: core::ops::Range<u8> = b.into_iter();

View file

@ -7,18 +7,18 @@ fn main() {
// Unchanged
let a: core::range::RangeFull = ..;
let b: core::range::RangeTo<u8> = ..2;
let c: core::range::RangeToInclusive<u8> = ..=3;
let _: core::ops::RangeFull = a;
let _: core::ops::RangeTo<u8> = b;
let _: core::ops::RangeToInclusive<u8> = c;
// Changed
let a: core::range::RangeFrom<u8> = 1..;
let b: core::range::Range<u8> = 2..3;
let c: core::range::RangeInclusive<u8> = 4..=5;
let d: core::range::RangeToInclusive<u8> = ..=3;
let _: core::range::IterRangeFrom<u8> = a.into_iter();
let _: core::range::IterRange<u8> = b.into_iter();
let _: core::range::IterRangeInclusive<u8> = c.into_iter();
// RangeToInclusive has no Iterator implementation
}

View file

@ -207,7 +207,7 @@ LL | take_range(std::ops::RangeToInclusive { end: 5 });
| arguments to this function are incorrect
|
= note: expected reference `&_`
found struct `RangeToInclusive<{integer}>`
found struct `std::ops::RangeToInclusive<{integer}>`
note: function defined here
--> $DIR/issue-54505-no-literals.rs:12:4
|
@ -227,7 +227,7 @@ LL | take_range(::std::ops::RangeToInclusive { end: 5 });
| arguments to this function are incorrect
|
= note: expected reference `&_`
found struct `RangeToInclusive<{integer}>`
found struct `std::ops::RangeToInclusive<{integer}>`
note: function defined here
--> $DIR/issue-54505-no-literals.rs:12:4
|

View file

@ -112,7 +112,7 @@ LL | take_range(..=42);
| arguments to this function are incorrect
|
= note: expected reference `&_`
found struct `RangeToInclusive<{integer}>`
found struct `core::ops::RangeToInclusive<{integer}>`
note: function defined here
--> $DIR/issue-54505-no-std.rs:25:4
|

View file

@ -112,7 +112,7 @@ LL | take_range(..=42);
| arguments to this function are incorrect
|
= note: expected reference `&_`
found struct `RangeToInclusive<{integer}>`
found struct `std::ops::RangeToInclusive<{integer}>`
note: function defined here
--> $DIR/issue-54505.rs:10:4
|

View file

@ -0,0 +1,26 @@
//@ run-pass
#![feature(static_align)]
#[rustc_align_static(64)]
static A: u8 = 0;
#[rustc_align_static(64)]
static B: u8 = 0;
#[rustc_align_static(128)]
#[no_mangle]
static EXPORTED: u64 = 0;
unsafe extern "C" {
#[rustc_align_static(128)]
#[link_name = "EXPORTED"]
static C: u64;
}
fn main() {
assert!(core::ptr::from_ref(&A).addr().is_multiple_of(64));
assert!(core::ptr::from_ref(&B).addr().is_multiple_of(64));
assert!(core::ptr::from_ref(&EXPORTED).addr().is_multiple_of(128));
unsafe { assert!(core::ptr::from_ref(&C).addr().is_multiple_of(128)) };
}