Merge pull request #4832 from rust-lang/rustup-2026-01-25

Automatic Rustup
This commit is contained in:
Ralf Jung 2026-01-25 09:05:57 +00:00 committed by GitHub
commit a109785719
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
362 changed files with 8518 additions and 2816 deletions

View file

@ -630,7 +630,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "clippy"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"anstream",
"askama",
@ -657,7 +657,7 @@ dependencies = [
[[package]]
name = "clippy_config"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"clippy_utils",
"itertools",
@ -681,7 +681,7 @@ dependencies = [
[[package]]
name = "clippy_lints"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.1",
@ -713,7 +713,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"arrayvec",
"itertools",
@ -1117,7 +1117,7 @@ dependencies = [
[[package]]
name = "declare_clippy_lint"
version = "0.1.94"
version = "0.1.95"
[[package]]
name = "derive-where"

View file

@ -3626,6 +3626,7 @@ impl Item {
pub fn opt_generics(&self) -> Option<&Generics> {
match &self.kind {
ItemKind::ExternCrate(..)
| ItemKind::ConstBlock(_)
| ItemKind::Use(_)
| ItemKind::Mod(..)
| ItemKind::ForeignMod(_)
@ -3895,6 +3896,17 @@ impl ConstItemRhs {
}
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct ConstBlockItem {
pub id: NodeId,
pub span: Span,
pub block: Box<Block>,
}
impl ConstBlockItem {
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
}
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
@ -3914,6 +3926,11 @@ pub enum ItemKind {
///
/// E.g., `const FOO: i32 = 42;`.
Const(Box<ConstItem>),
/// A module-level const block.
/// Equivalent to `const _: () = const { ... };`.
///
/// E.g., `const { assert!(true) }`.
ConstBlock(ConstBlockItem),
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
@ -3990,6 +4007,8 @@ impl ItemKind {
| ItemKind::MacroDef(ident, _)
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT),
ItemKind::Use(_)
| ItemKind::ForeignMod(_)
| ItemKind::GlobalAsm(_)
@ -4003,9 +4022,9 @@ impl ItemKind {
pub fn article(&self) -> &'static str {
use ItemKind::*;
match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
| Delegation(..) | DelegationMac(..) => "a",
Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..)
| GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..)
| MacroDef(..) | Delegation(..) | DelegationMac(..) => "a",
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
}
}
@ -4016,6 +4035,7 @@ impl ItemKind {
ItemKind::Use(..) => "`use` import",
ItemKind::Static(..) => "static item",
ItemKind::Const(..) => "constant item",
ItemKind::ConstBlock(..) => "const block",
ItemKind::Fn(..) => "function",
ItemKind::Mod(..) => "module",
ItemKind::ForeignMod(..) => "extern block",
@ -4045,7 +4065,18 @@ impl ItemKind {
| Self::Trait(box Trait { generics, .. })
| Self::TraitAlias(box TraitAlias { generics, .. })
| Self::Impl(Impl { generics, .. }) => Some(generics),
_ => None,
Self::ExternCrate(..)
| Self::Use(..)
| Self::Static(..)
| Self::ConstBlock(..)
| Self::Mod(..)
| Self::ForeignMod(..)
| Self::GlobalAsm(..)
| Self::MacCall(..)
| Self::MacroDef(..)
| Self::Delegation(..)
| Self::DelegationMac(..) => None,
}
}
}

View file

@ -425,6 +425,7 @@ macro_rules! common_visitor_and_walkers {
ByRef,
Closure,
Const,
ConstBlockItem,
ConstItem,
ConstItemRhs,
Defaultness,
@ -825,6 +826,8 @@ macro_rules! common_visitor_and_walkers {
visit_visitable!($($mut)? vis, use_tree),
ItemKind::Static(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::ConstBlock(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::Const(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::Mod(safety, ident, mod_kind) =>

View file

@ -205,6 +205,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
| ItemKind::Use(..)
| ItemKind::Static(..)
| ItemKind::Const(..)
| ItemKind::ConstBlock(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod(..)
| ItemKind::GlobalAsm(..)
@ -282,8 +283,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_define_opaque(hir_id, define_opaque);
hir::ItemKind::Static(*m, ident, ty, body_id)
}
ItemKind::Const(box ast::ConstItem {
ident, generics, ty, rhs, define_opaque, ..
ItemKind::Const(box ConstItem {
defaultness: _,
ident,
generics,
ty,
rhs,
define_opaque,
}) => {
let ident = self.lower_ident(*ident);
let (generics, (ty, rhs)) = self.lower_generics(
@ -302,6 +308,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_define_opaque(hir_id, &define_opaque);
hir::ItemKind::Const(ident, generics, ty, rhs)
}
ItemKind::ConstBlock(ConstBlockItem { span, id, block }) => hir::ItemKind::Const(
self.lower_ident(ConstBlockItem::IDENT),
hir::Generics::empty(),
self.arena.alloc(self.ty_tup(DUMMY_SP, &[])),
hir::ConstItemRhs::Body({
let body = hir::Expr {
hir_id: self.lower_node_id(*id),
kind: hir::ExprKind::Block(self.lower_block(block, false), None),
span: self.lower_span(*span),
};
self.record_body(&[], body)
}),
),
ItemKind::Fn(box Fn {
sig: FnSig { decl, header, span: fn_sig_span },
ident,

View file

@ -537,6 +537,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(super_let, "`super let` is experimental");
gate_all!(frontmatter, "frontmatters are experimental");
gate_all!(coroutines, "coroutine syntax is experimental");
gate_all!(const_block_items, "const block items are experimental");
if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -205,6 +205,17 @@ impl<'a> State<'a> {
define_opaque.as_deref(),
);
}
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
let ib = self.ibox(INDENT_UNIT);
self.word("const");
self.nbsp();
{
let cb = self.cbox(0);
let ib = self.ibox(0);
self.print_block_with_attrs(block, &[], cb, ib);
}
self.end(ib);
}
ast::ItemKind::Const(box ast::ConstItem {
defaultness,
ident,

View file

@ -360,7 +360,8 @@ fn parse_cfg_attr_internal<'a>(
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
// Parse cfg predicate
let pred_start = parser.token.span;
let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
let meta =
MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints { recover: true })?;
let pred_span = pred_start.with_hi(parser.token.span.hi());
let cfg_predicate = AttributeParser::parse_single_args(
@ -375,7 +376,7 @@ fn parse_cfg_attr_internal<'a>(
CRATE_NODE_ID,
Target::Crate,
features,
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
&meta,
parse_cfg_entry,
&CFG_ATTR_TEMPLATE,

View file

@ -78,8 +78,9 @@ pub fn parse_cfg_select(
}
}
} else {
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
.map_err(|diag| diag.emit())?;
let meta =
MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints { recover: true })
.map_err(|diag| diag.emit())?;
let cfg_span = meta.span();
let cfg = AttributeParser::parse_single_args(
sess,
@ -94,7 +95,7 @@ pub fn parse_cfg_select(
// Doesn't matter what the target actually is here.
Target::Crate,
features,
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
&meta,
parse_cfg_entry,
&AttributeTemplate::default(),

View file

@ -381,7 +381,7 @@ impl Stage for Late {
}
fn should_emit(&self) -> ShouldEmit {
ShouldEmit::ErrorsAndLints
ShouldEmit::ErrorsAndLints { recover: true }
}
}
@ -438,7 +438,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
if !matches!(
self.stage.should_emit(),
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
) {
return;
}
@ -765,9 +765,18 @@ pub enum ShouldEmit {
EarlyFatal { also_emit_lints: bool },
/// The operation will emit errors and lints.
/// This is usually what you need.
ErrorsAndLints,
/// The operation will emit *not* errors and lints.
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
ErrorsAndLints {
/// Whether [`ArgParser`] will attempt to recover from errors.
///
/// If true, it will attempt to recover from bad input (like an invalid literal). Setting
/// this to false will instead return early, and not raise errors except at the top level
/// (in [`ArgParser::from_attr_args`]).
recover: bool,
},
/// The operation will *not* emit errors and lints.
///
/// The parser can still call `delay_bug`, so you *must* ensure that this operation will also be
/// called with `ShouldEmit::ErrorsAndLints`.
Nothing,
}
@ -776,7 +785,7 @@ impl ShouldEmit {
match self {
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
ShouldEmit::ErrorsAndLints => diag.emit(),
ShouldEmit::ErrorsAndLints { .. } => diag.emit(),
ShouldEmit::Nothing => diag.delay_as_bug(),
}
}

View file

@ -16,7 +16,7 @@ use rustc_errors::{Diag, PResult};
use rustc_hir::{self as hir, AttrPath};
use rustc_parse::exp;
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
use rustc_session::errors::{create_lit_error, report_lit_error};
use rustc_session::errors::create_lit_error;
use rustc_session::parse::ParseSess;
use rustc_span::{Ident, Span, Symbol, sym};
use thin_vec::ThinVec;
@ -113,16 +113,29 @@ impl ArgParser {
Some(match value {
AttrArgs::Empty => Self::NoArgs,
AttrArgs::Delimited(args) => {
// The arguments of rustc_dummy and diagnostic::do_not_recommend are not validated
// if the arguments are delimited.
// See https://doc.rust-lang.org/reference/attributes/diagnostics.html#r-attributes.diagnostic.namespace.unknown-invalid-syntax
if parts == &[sym::rustc_dummy]
|| parts == &[sym::diagnostic, sym::do_not_recommend]
{
return Some(ArgParser::List(MetaItemListParser {
sub_parsers: ThinVec::new(),
span: args.dspan.entire(),
}));
// Diagnostic attributes can't error if they encounter non meta item syntax.
// However, the current syntax for diagnostic attributes is meta item syntax.
// Therefore we can substitute with a dummy value on invalid syntax.
if matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
match MetaItemListParser::new(
&args.tokens,
args.dspan.entire(),
psess,
ShouldEmit::ErrorsAndLints { recover: false },
) {
Ok(p) => return Some(ArgParser::List(p)),
Err(e) => {
// We can just dispose of the diagnostic and not bother with a lint,
// because this will look like `#[diagnostic::attr()]` was used. This
// is invalid for all diagnostic attrs, so a lint explaining the proper
// form will be issued later.
e.cancel();
return Some(ArgParser::List(MetaItemListParser {
sub_parsers: ThinVec::new(),
span: args.dspan.entire(),
}));
}
}
}
if args.delim != Delimiter::Parenthesis {
@ -141,7 +154,9 @@ impl ArgParser {
}
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
eq_span: *eq_span,
value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
value: expr_to_lit(psess, &expr, expr.span, should_emit)
.map_err(|e| should_emit.emit_err(e))
.ok()??,
value_span: expr.span,
}),
})
@ -336,58 +351,53 @@ impl NameValueParser {
}
}
fn expr_to_lit(
psess: &ParseSess,
fn expr_to_lit<'sess>(
psess: &'sess ParseSess,
expr: &Expr,
span: Span,
should_emit: ShouldEmit,
) -> Option<MetaItemLit> {
) -> PResult<'sess, Option<MetaItemLit>> {
if let ExprKind::Lit(token_lit) = expr.kind {
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
match res {
Ok(lit) => {
if token_lit.suffix.is_some() {
should_emit.emit_err(
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
);
None
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
} else {
if !lit.kind.is_unsuffixed() {
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
should_emit.emit_err(
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
);
if lit.kind.is_unsuffixed() {
Ok(Some(lit))
} else {
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
}
Some(lit)
}
}
Err(err) => {
let guar = report_lit_error(psess, err, token_lit, expr.span);
let lit = MetaItemLit {
symbol: token_lit.symbol,
suffix: token_lit.suffix,
kind: LitKind::Err(guar),
span: expr.span,
};
Some(lit)
let err = create_lit_error(psess, err, token_lit, expr.span);
if matches!(should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
Err(err)
} else {
let lit = MetaItemLit {
symbol: token_lit.symbol,
suffix: token_lit.suffix,
kind: LitKind::Err(err.emit()),
span: expr.span,
};
Ok(Some(lit))
}
}
}
} else {
if matches!(should_emit, ShouldEmit::Nothing) {
return None;
return Ok(None);
}
// Example cases:
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
// - `#[foo = include_str!("nonexistent-file.rs")]`:
// results in `ast::ExprKind::Err`. In that case we delay
// the error because an earlier error will have already
// been reported.
// results in `ast::ExprKind::Err`.
let msg = "attribute value must be a literal";
let err = psess.dcx().struct_span_err(span, msg);
should_emit.emit_err(err);
None
Err(err)
}
}
@ -420,9 +430,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
if !lit.kind.is_unsuffixed() {
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
self.should_emit.emit_err(
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
);
let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
if matches!(self.should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
return Err(err);
} else {
self.should_emit.emit_err(err)
};
}
Ok(lit)

View file

@ -45,7 +45,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
{
localize_statement_constraint(
tcx,
body,
stmt,
&outlives_constraint,
point,
@ -74,7 +73,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
/// needed CFG `from`-`to` intra-block nodes.
fn localize_statement_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
stmt: &Statement<'tcx>,
outlives_constraint: &OutlivesConstraint<'tcx>,
current_point: PointIndex,
@ -114,28 +112,22 @@ fn localize_statement_constraint<'tcx>(
},
"there should be no common regions between the LHS and RHS of an assignment"
);
let lhs_ty = body.local_decls[lhs.local].ty;
let successor_point = current_point;
compute_constraint_direction(
tcx,
outlives_constraint,
&lhs_ty,
current_point,
successor_point,
universal_regions,
)
}
_ => {
// For the other cases, we localize an outlives constraint to where it arises.
LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
}
// Assignments should be the only statement that can both generate constraints that
// apply on entry (specific to the RHS place) *and* others that only apply on exit (the
// subset of RHS regions that actually flow into the LHS): i.e., where midpoints would
// be used to ensure the former happen before the latter, within the same MIR Location.
}
}
// We generally localize an outlives constraint to where it arises.
LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
}
}
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
@ -150,14 +142,12 @@ fn localize_terminator_constraint<'tcx>(
universal_regions: &UniversalRegions<'tcx>,
) -> LocalizedOutlivesConstraint {
// FIXME: check if other terminators need the same handling as `Call`s, in particular
// Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some
// coroutine tests, and that may be why.
// Assert/Yield/Drop.
match &terminator.kind {
// FIXME: also handle diverging calls.
TerminatorKind::Call { destination, target: Some(target), .. } => {
// Calls are similar to assignments, and thus follow the same pattern. If there is a
// target for the call we also relate what flows into the destination here to entry to
// that successor.
// If there is a target for the call we also relate what flows into the destination here
// to entry to that successor.
let destination_ty = destination.ty(&body.local_decls, tcx);
let successor_location = Location { block: *target, statement_index: 0 };
let successor_point = liveness.point_from_location(successor_location);

View file

@ -40,8 +40,11 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
return Err(cx.dcx().emit_err(errors::RequiresCfgPattern { span }));
}
let meta = MetaItemOrLitParser::parse_single(&mut parser, ShouldEmit::ErrorsAndLints)
.map_err(|diag| diag.emit())?;
let meta = MetaItemOrLitParser::parse_single(
&mut parser,
ShouldEmit::ErrorsAndLints { recover: true },
)
.map_err(|diag| diag.emit())?;
let cfg = AttributeParser::parse_single_args(
cx.sess,
span,
@ -55,7 +58,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
// Doesn't matter what the target actually is here.
Target::Crate,
Some(cx.ecfg.features),
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
&meta,
parse_cfg_entry,
&CFG_TEMPLATE,

View file

@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure;
use rustc_feature::Features;
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
use rustc_session::Session;
use rustc_span::{Span, sym};
use smallvec::SmallVec;
@ -110,7 +110,8 @@ impl CfgEval<'_> {
let res: PResult<'_, Annotatable> = try {
match annotatable {
Annotatable::Item(_) => {
let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
let item =
parser.parse_item(ForceCollect::Yes, AllowConstBlockItems::Yes)?.unwrap();
Annotatable::Item(self.flat_map_item(item).pop().unwrap())
}
Annotatable::AssocItem(_, ctxt) => {

View file

@ -13,7 +13,7 @@ use rustc_expand::base::{
};
use rustc_expand::module::DirOwnership;
use rustc_parse::lexer::StripTokens;
use rustc_parse::parser::ForceCollect;
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect};
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
use rustc_session::parse::ParseSess;
@ -168,7 +168,7 @@ pub(crate) fn expand_include<'cx>(
));
let mut ret = SmallVec::new();
loop {
match p.parse_item(ForceCollect::No) {
match p.parse_item(ForceCollect::No, AllowConstBlockItems::Yes) {
Err(err) => {
err.emit();
break;

View file

@ -348,6 +348,31 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
ret.write_cvalue(fx, ret_lane);
}
sym::simd_splat => {
intrinsic_args!(fx, args => (value); intrinsic);
if !ret.layout().ty.is_simd() {
report_simd_type_validation_error(fx, intrinsic, span, ret.layout().ty);
return;
}
let (lane_count, lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
if value.layout().ty != lane_ty {
fx.tcx.dcx().span_fatal(
span,
format!(
"[simd_splat] expected element type {lane_ty:?}, got {got:?}",
got = value.layout().ty
),
);
}
for i in 0..lane_count {
let ret_lane = ret.place_lane(fx, i.into());
ret_lane.write_cvalue(fx, value);
}
}
sym::simd_neg
| sym::simd_bswap
| sym::simd_bitreverse

View file

@ -121,6 +121,42 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
return Ok(bx.vector_select(vector_mask, arg1, args[2].immediate()));
}
#[cfg(feature = "master")]
if name == sym::simd_splat {
let (out_len, out_ty) = require_simd2!(ret_ty, SimdReturn);
require!(
args[0].layout.ty == out_ty,
InvalidMonomorphization::ExpectedVectorElementType {
span,
name,
expected_element: out_ty,
vector_type: ret_ty,
}
);
let vec_ty = llret_ty.unqualified().dyncast_vector().expect("vector return type");
let elem_ty = vec_ty.get_element_type();
// Cast pointer type to usize (GCC does not support pointer SIMD vectors).
let value = args[0];
let scalar = if value.layout.ty.is_numeric() {
value.immediate()
} else if value.layout.ty.is_raw_ptr() {
bx.ptrtoint(value.immediate(), elem_ty)
} else {
return_error!(InvalidMonomorphization::UnsupportedOperation {
span,
name,
in_ty: ret_ty,
in_elem: value.layout.ty
});
};
let elements = vec![scalar; out_len as usize];
return Ok(bx.context.new_rvalue_from_vector(bx.location, llret_ty, &elements));
}
// every intrinsic below takes a SIMD vector as its first argument
require_simd!(
args[0].layout.ty,

View file

@ -39,6 +39,7 @@ impl OwnedTargetMachine {
debug_info_compression: llvm::CompressionKind,
use_emulated_tls: bool,
use_wasm_eh: bool,
large_data_threshold: u64,
) -> Result<Self, LlvmError<'static>> {
// SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
let tm_ptr = unsafe {
@ -65,6 +66,7 @@ impl OwnedTargetMachine {
debug_info_compression,
use_emulated_tls,
use_wasm_eh,
large_data_threshold,
)
};

View file

@ -275,6 +275,8 @@ pub(crate) fn target_machine_factory(
let use_wasm_eh = wants_wasm_eh(sess);
let large_data_threshold = sess.opts.unstable_opts.large_data_threshold.unwrap_or(0);
let prof = SelfProfilerRef::clone(&sess.prof);
Arc::new(move |config: TargetMachineFactoryConfig| {
// Self-profile timer for invoking a factory to create a target machine.
@ -316,6 +318,7 @@ pub(crate) fn target_machine_factory(
debuginfo_compression,
use_emulated_tls,
use_wasm_eh,
large_data_threshold,
)
})
}

View file

@ -665,8 +665,8 @@ impl MsvcBasicName for ty::UintTy {
impl MsvcBasicName for ty::FloatTy {
fn msvc_basic_name(self) -> &'static str {
// FIXME(f16_f128): `f16` and `f128` have no MSVC representation. We could improve the
// debuginfo. See: <https://github.com/rust-lang/rust/issues/121837>
// FIXME(f128): `f128` has no MSVC representation. We could improve the debuginfo.
// See: <https://github.com/rust-lang/rust/issues/121837>
match self {
ty::FloatTy::F16 => {
bug!("`f16` should have been handled in `build_basic_type_di_node`")

View file

@ -1581,6 +1581,31 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
}
if name == sym::simd_splat {
let (_out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
require!(
args[0].layout.ty == out_ty,
InvalidMonomorphization::ExpectedVectorElementType {
span,
name,
expected_element: out_ty,
vector_type: ret_ty,
}
);
// `insertelement <N x elem> poison, elem %x, i32 0`
let poison_vec = bx.const_poison(llret_ty);
let idx0 = bx.const_i32(0);
let v0 = bx.insert_element(poison_vec, args[0].immediate(), idx0);
// `shufflevector <N x elem> v0, <N x elem> poison, <N x i32> zeroinitializer`
// The masks is all zeros, so this splats lane 0 (which has our element in it).
let splat = bx.shuffle_vector(v0, poison_vec, bx.const_null(llret_ty));
return Ok(splat);
}
// every intrinsic below takes a SIMD vector as its first argument
let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput);
let in_ty = args[0].layout.ty;

View file

@ -2347,6 +2347,7 @@ unsafe extern "C" {
DebugInfoCompression: CompressionKind,
UseEmulatedTls: bool,
UseWasmEH: bool,
LargeDataThreshold: u64,
) -> *mut TargetMachine;
pub(crate) fn LLVMRustAddLibraryInfo<'a>(

View file

@ -1827,9 +1827,9 @@ fn exported_symbols_for_non_proc_macro(
// Mark allocator shim symbols as exported only if they were generated.
if export_threshold == SymbolExportLevel::Rust
&& needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type)
&& tcx.allocator_kind(()).is_some()
&& let Some(kind) = tcx.allocator_kind(())
{
symbols.extend(allocator_shim_symbols(tcx));
symbols.extend(allocator_shim_symbols(tcx, kind));
}
symbols

View file

@ -118,8 +118,10 @@ pub(super) fn exported_symbols_for_lto(
}
// Mark allocator shim symbols as exported only if they were generated.
if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() {
symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name));
if export_threshold == SymbolExportLevel::Rust
&& let Some(kind) = allocator_kind_for_codegen(tcx)
{
symbols_below_threshold.extend(allocator_shim_symbols(tcx, kind).map(|(name, _kind)| name));
}
symbols_below_threshold

View file

@ -1,9 +1,7 @@
use std::collections::hash_map::Entry::*;
use rustc_abi::{CanonAbi, X86Call};
use rustc_ast::expand::allocator::{
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name,
};
use rustc_ast::expand::allocator::{AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name};
use rustc_data_structures::unord::UnordMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId};
@ -21,6 +19,7 @@ use rustc_target::spec::{Arch, Os, TlsModel};
use tracing::debug;
use crate::back::symbol_export;
use crate::base::allocator_shim_contents;
fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
crates_export_threshold(tcx.crate_types())
@ -490,14 +489,12 @@ pub(crate) fn provide(providers: &mut Providers) {
pub(crate) fn allocator_shim_symbols(
tcx: TyCtxt<'_>,
kind: AllocatorKind,
) -> impl Iterator<Item = (String, SymbolExportKind)> {
ALLOCATOR_METHODS
.iter()
allocator_shim_contents(tcx, kind)
.into_iter()
.map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
.chain([
mangle_internal_symbol(tcx, global_fn_name(ALLOC_ERROR_HANDLER).as_str()),
mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
])
.chain([mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE)])
.map(move |symbol_name| {
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));

View file

@ -1074,8 +1074,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if constant_ty.is_simd() {
// However, some SIMD types do not actually use the vector ABI
// (in particular, packed SIMD types do not). Ensure we exclude those.
//
// We also have to exclude vectors of pointers because `immediate_const_vector`
// does not work for those.
let layout = bx.layout_of(constant_ty);
if let BackendRepr::SimdVector { .. } = layout.backend_repr {
let (_, element_ty) = constant_ty.simd_size_and_type(bx.tcx());
if let BackendRepr::SimdVector { .. } = layout.backend_repr
&& element_ty.is_numeric()
{
let (llval, ty) = self.immediate_const_vector(bx, constant);
return OperandRef {
val: OperandValue::Immediate(llval),

View file

@ -61,6 +61,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
self.copy_op(&self.project_index(&input, index)?, &dest)?;
}
sym::simd_splat => {
let elem = &args[0];
let (dest, dest_len) = self.project_to_simd(&dest)?;
for i in 0..dest_len {
let place = self.project_index(&dest, i)?;
self.copy_op(elem, &place)?;
}
}
sym::simd_neg
| sym::simd_fabs
| sym::simd_ceil

View file

@ -22,7 +22,7 @@ use rustc_hir::limit::Limit;
use rustc_hir::{Stability, find_attr};
use rustc_lint_defs::RegisteredTools;
use rustc_parse::MACRO_ARGUMENTS;
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
use rustc_session::Session;
use rustc_session::parse::ParseSess;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
@ -1472,7 +1472,7 @@ pub(crate) fn stream_pretty_printing_compatibility_hack(
let mut parser = Parser::new(psess, stream.clone(), None);
// No need to collect tokens for this simple check.
parser
.parse_item(ForceCollect::No)
.parse_item(ForceCollect::No, AllowConstBlockItems::No)
.expect("failed to reparse item")
.expect("an actual item")
}

View file

@ -393,9 +393,10 @@ impl<'a> StripUnconfigured<'a> {
/// Determines if a node with the given attributes should be included in this configuration.
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs
.iter()
.all(|attr| !is_cfg(attr) || self.cfg_true(attr, ShouldEmit::ErrorsAndLints).as_bool())
attrs.iter().all(|attr| {
!is_cfg(attr)
|| self.cfg_true(attr, ShouldEmit::ErrorsAndLints { recover: true }).as_bool()
})
}
pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> EvalConfigResult {

View file

@ -25,8 +25,8 @@ use rustc_hir::Target;
use rustc_hir::def::MacroKinds;
use rustc_hir::limit::Limit;
use rustc_parse::parser::{
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
token_descr,
AllowConstBlockItems, AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser,
RecoverColon, RecoverComma, token_descr,
};
use rustc_session::Session;
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
@ -1099,7 +1099,7 @@ pub fn parse_ast_fragment<'a>(
Ok(match kind {
AstFragmentKind::Items => {
let mut items = SmallVec::new();
while let Some(item) = this.parse_item(ForceCollect::No)? {
while let Some(item) = this.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)? {
items.push(item);
}
AstFragment::Items(items)
@ -2170,7 +2170,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
call.span(),
self.cx.current_expansion.lint_node_id,
Some(self.cx.ecfg.features),
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
);
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
@ -2220,7 +2220,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// Target doesn't matter for `cfg` parsing.
Target::Crate,
self.cfg().features,
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
parse_cfg,
&CFG_TEMPLATE,
) else {

View file

@ -1,7 +1,7 @@
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::ErrorGuaranteed;
use rustc_middle::ty::{self, TyCtxt};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
use rustc_session::Session;
use rustc_session::config::ProcMacroExecutionStrategy;
use rustc_span::profiling::SpannedEventArgRecorder;
@ -160,7 +160,10 @@ impl MultiItemModifier for DeriveProcMacro {
let mut items = vec![];
loop {
match parser.parse_item(ForceCollect::No) {
match parser.parse_item(
ForceCollect::No,
if is_stmt { AllowConstBlockItems::No } else { AllowConstBlockItems::Yes },
) {
Ok(None) => break,
Ok(Some(item)) => {
if is_stmt {

View file

@ -414,6 +414,8 @@ declare_features! (
(unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)),
/// Allows `async {}` expressions in const contexts.
(unstable, const_async_blocks, "1.53.0", Some(85368)),
/// Allows `const { ... }` as a shorthand for `const _: () = const { ... };` for module items.
(unstable, const_block_items, "CURRENT_RUSTC_VERSION", Some(149226)),
/// Allows `const || {}` closures in const contexts.
(incomplete, const_closures, "1.68.0", Some(106003)),
/// Allows using `[const] Destruct` bounds and calling drop impls in const contexts.

View file

@ -171,6 +171,7 @@ impl Target {
ast::ItemKind::Use(..) => Target::Use,
ast::ItemKind::Static { .. } => Target::Static,
ast::ItemKind::Const(..) => Target::Const,
ast::ItemKind::ConstBlock(..) => Target::Const,
ast::ItemKind::Fn { .. } => Target::Fn,
ast::ItemKind::Mod(..) => Target::Mod,
ast::ItemKind::ForeignMod { .. } => Target::ForeignMod,

View file

@ -746,6 +746,7 @@ pub(crate) fn check_intrinsic_type(
sym::simd_extract | sym::simd_extract_dyn => {
(2, 0, vec![param(0), tcx.types.u32], param(1))
}
sym::simd_splat => (2, 0, vec![param(1)], param(0)),
sym::simd_cast
| sym::simd_as
| sym::simd_cast_ptr

View file

@ -305,7 +305,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray,
const char *SplitDwarfFile, const char *OutputObjFile,
LLVMRustCompressionKind DebugInfoCompression, bool UseEmulatedTls,
bool UseWasmEH) {
bool UseWasmEH, uint64_t LargeDataThreshold) {
auto OptLevel = fromRust(RustOptLevel);
auto RM = fromRust(RustReloc);
@ -381,6 +381,11 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
TargetMachine *TM = TheTarget->createTargetMachine(
Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel);
#endif
if (LargeDataThreshold != 0) {
TM->setLargeDataThreshold(LargeDataThreshold);
}
return wrap(TM);
}

View file

@ -4,10 +4,9 @@ use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::OwnerId;
use rustc_macros::HashStable;
use rustc_query_system::HandleCycleError;
use rustc_query_system::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
pub(crate) use rustc_query_system::query::QueryJobId;
use rustc_query_system::query::*;
use rustc_query_system::query::{CycleError, CycleErrorHandling, HashResult, QueryCache};
use rustc_span::{ErrorGuaranteed, Span};
pub use sealed::IntoQueryParam;
@ -23,7 +22,8 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
pub name: &'static str,
pub eval_always: bool,
pub dep_kind: DepKind,
pub handle_cycle_error: HandleCycleError,
/// How this query deals with query cycle errors.
pub cycle_error_handling: CycleErrorHandling,
// Offset of this query's state field in the QueryStates struct
pub query_state: usize,
// Offset of this query's cache field in the QueryCaches struct

View file

@ -807,12 +807,22 @@ pub enum PatKind<'tcx> {
subpatterns: Vec<FieldPat<'tcx>>,
},
/// `box P`, `&P`, `&mut P`, etc.
/// Explicit or implicit `&P` or `&mut P`, for some subpattern `P`.
///
/// Implicit `&`/`&mut` patterns can be inserted by match-ergonomics.
///
/// With `feature(pin_ergonomics)`, this can also be `&pin const P` or
/// `&pin mut P`, as indicated by the `pin` field.
Deref {
#[type_visitable(ignore)]
pin: hir::Pinnedness,
subpattern: Box<Pat<'tcx>>,
},
/// Deref pattern, written `box P` for now.
/// Explicit or implicit `deref!(..)` pattern, under `feature(deref_patterns)`.
/// Represents a call to `Deref` or `DerefMut`, or a deref-move of `Box`.
///
/// `box P` patterns also lower to this, under `feature(box_patterns)`.
DerefPattern {
subpattern: Box<Pat<'tcx>>,
/// Whether the pattern scrutinee needs to be borrowed in order to call `Deref::deref` or

View file

@ -268,7 +268,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
| PatKind::Error(_) => {}
PatKind::Binding { subpattern: Some(subpattern), .. }
| PatKind::Deref { subpattern }
| PatKind::Deref { subpattern, .. }
| PatKind::DerefPattern { subpattern, .. } => callback(subpattern),
PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {

View file

@ -2,6 +2,7 @@ use std::sync::Arc;
use rustc_abi::FieldIdx;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
@ -314,23 +315,24 @@ impl<'tcx> MatchPairTree<'tcx> {
None
}
// FIXME: Pin-patterns should probably have their own pattern kind,
// instead of overloading `PatKind::Deref` via the pattern type.
PatKind::Deref { ref subpattern }
if let Some(ref_ty) = pattern.ty.pinned_ty()
&& ref_ty.is_ref() =>
{
PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
let pinned_ref_ty = match pattern.ty.pinned_ty() {
Some(p_ty) if p_ty.is_ref() => p_ty,
_ => span_bug!(pattern.span, "bad type for pinned deref: {:?}", pattern.ty),
};
MatchPairTree::for_pattern(
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
// Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`.
place_builder.field(FieldIdx::ZERO, pinned_ref_ty).deref(),
subpattern,
cx,
&mut subpairs,
extra_data,
);
None
}
PatKind::Deref { ref subpattern }
PatKind::Deref { pin: Pinnedness::Not, ref subpattern }
| PatKind::DerefPattern { ref subpattern, borrow: DerefPatBorrowMode::Box } => {
MatchPairTree::for_pattern(
place_builder.deref(),

View file

@ -10,7 +10,7 @@ use std::mem;
use std::sync::Arc;
use itertools::{Itertools, Position};
use rustc_abi::{FIRST_VARIANT, VariantIdx};
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use rustc_data_structures::debug_assert_matches;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
@ -909,7 +909,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| PatKind::Never
| PatKind::Error(_) => {}
PatKind::Deref { ref subpattern } => {
PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
// Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`.
visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f);
}
PatKind::Deref { pin: Pinnedness::Not, ref subpattern } => {
visit_subpat(self, subpattern, &user_tys.deref(), f);
}

View file

@ -294,8 +294,12 @@ impl<'tcx> ConstToPat<'tcx> {
|| pointee_ty.is_slice()
|| pointee_ty.is_sized(tcx, self.typing_env)
{
// References have the same valtree representation as their pointee.
PatKind::Deref {
// This node has type `ty::Ref`, so it's not a pin-deref.
pin: hir::Pinnedness::Not,
// Lower the valtree to a pattern as the pointee type.
// This works because references have the same valtree
// representation as their pointee.
subpattern: self.valtree_to_pat(ty::Value { ty: *pointee_ty, valtree }),
}
} else {

View file

@ -132,12 +132,16 @@ impl<'tcx> PatCtxt<'tcx> {
debug!("{:?}: wrapping pattern with adjustment {:?}", thir_pat, adjust);
let span = thir_pat.span;
let kind = match adjust.kind {
PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat },
PatAdjust::BuiltinDeref => {
PatKind::Deref { pin: hir::Pinnedness::Not, subpattern: thir_pat }
}
PatAdjust::OverloadedDeref => {
let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat);
PatKind::DerefPattern { subpattern: thir_pat, borrow }
}
PatAdjust::PinDeref => PatKind::Deref { subpattern: thir_pat },
PatAdjust::PinDeref => {
PatKind::Deref { pin: hir::Pinnedness::Pinned, subpattern: thir_pat }
}
};
Box::new(Pat { span, ty: adjust.source, kind, extra: None })
});
@ -334,7 +338,7 @@ impl<'tcx> PatCtxt<'tcx> {
let borrow = self.typeck_results.deref_pat_borrow_mode(ty, subpattern);
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), borrow }
}
hir::PatKind::Ref(subpattern, _, _) => {
hir::PatKind::Ref(subpattern, pin, _) => {
// Track the default binding mode for the Rust 2024 migration suggestion.
let opt_old_mode_span =
self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
@ -342,7 +346,7 @@ impl<'tcx> PatCtxt<'tcx> {
if let Some(s) = &mut self.rust_2024_migration {
s.leave_ref(opt_old_mode_span);
}
PatKind::Deref { subpattern }
PatKind::Deref { pin, subpattern }
}
hir::PatKind::Box(subpattern) => PatKind::DerefPattern {
subpattern: self.lower_pattern(subpattern),

View file

@ -774,8 +774,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "]", depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
PatKind::Deref { subpattern } => {
PatKind::Deref { pin, subpattern } => {
print_indented!(self, "Deref { ", depth_lvl + 1);
print_indented!(self, format_args!("pin: {pin:?}"), depth_lvl + 2);
print_indented!(self, "subpattern:", depth_lvl + 2);
self.print_pat(subpattern, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);

View file

@ -9,7 +9,8 @@ use thin_vec::ThinVec;
use tracing::debug;
use super::{
AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos,
AllowConstBlockItems, AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle,
Trailing, UsePreAttrPos,
};
use crate::parser::FnContext;
use crate::{errors, exp, fluent_generated as fluent};
@ -203,6 +204,7 @@ impl<'a> Parser<'a> {
false,
FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true },
ForceCollect::No,
AllowConstBlockItems::Yes,
) {
Ok(Some(item)) => {
// FIXME(#100717)

View file

@ -22,8 +22,8 @@ use tracing::debug;
use super::diagnostics::{ConsumeClosingDelim, dummy_arg};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle,
Recovered, Trailing, UsePreAttrPos,
AllowConstBlockItems, AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect,
Parser, PathStyle, Recovered, Trailing, UsePreAttrPos,
};
use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};
use crate::{exp, fluent_generated as fluent};
@ -69,7 +69,7 @@ impl<'a> Parser<'a> {
// `parse_item` consumes the appropriate semicolons so any leftover is an error.
loop {
while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons
let Some(item) = self.parse_item(ForceCollect::No)? else {
let Some(item) = self.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)? else {
break;
};
items.push(item);
@ -123,21 +123,34 @@ enum ReuseKind {
}
impl<'a> Parser<'a> {
pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Box<Item>>> {
pub fn parse_item(
&mut self,
force_collect: ForceCollect,
allow_const_block_items: AllowConstBlockItems,
) -> PResult<'a, Option<Box<Item>>> {
let fn_parse_mode =
FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true };
self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(Box::new))
self.parse_item_(fn_parse_mode, force_collect, allow_const_block_items)
.map(|i| i.map(Box::new))
}
fn parse_item_(
&mut self,
fn_parse_mode: FnParseMode,
force_collect: ForceCollect,
const_block_items_allowed: AllowConstBlockItems,
) -> PResult<'a, Option<Item>> {
self.recover_vcs_conflict_marker();
let attrs = self.parse_outer_attributes()?;
self.recover_vcs_conflict_marker();
self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
self.parse_item_common(
attrs,
true,
false,
fn_parse_mode,
force_collect,
const_block_items_allowed,
)
}
pub(super) fn parse_item_common(
@ -147,10 +160,11 @@ impl<'a> Parser<'a> {
attrs_allowed: bool,
fn_parse_mode: FnParseMode,
force_collect: ForceCollect,
allow_const_block_items: AllowConstBlockItems,
) -> PResult<'a, Option<Item>> {
if let Some(item) =
self.eat_metavar_seq(MetaVarKind::Item, |this| this.parse_item(ForceCollect::Yes))
{
if let Some(item) = self.eat_metavar_seq(MetaVarKind::Item, |this| {
this.parse_item(ForceCollect::Yes, allow_const_block_items)
}) {
let mut item = item.expect("an actual item");
attrs.prepend_to_nt_inner(&mut item.attrs);
return Ok(Some(*item));
@ -163,6 +177,7 @@ impl<'a> Parser<'a> {
let kind = this.parse_item_kind(
&mut attrs,
mac_allowed,
allow_const_block_items,
lo,
&vis,
&mut def,
@ -209,6 +224,7 @@ impl<'a> Parser<'a> {
&mut self,
attrs: &mut AttrVec,
macros_allowed: bool,
allow_const_block_items: AllowConstBlockItems,
lo: Span,
vis: &Visibility,
def: &mut Defaultness,
@ -257,6 +273,15 @@ impl<'a> Parser<'a> {
} else if self.check_impl_frontmatter(0) {
// IMPL ITEM
self.parse_item_impl(attrs, def_(), false)?
} else if let AllowConstBlockItems::Yes | AllowConstBlockItems::DoesNotMatter =
allow_const_block_items
&& self.check_inline_const(0)
{
// CONST BLOCK ITEM
if let AllowConstBlockItems::DoesNotMatter = allow_const_block_items {
debug!("Parsing a const block item that does not matter: {:?}", self.token.span);
};
ItemKind::ConstBlock(self.parse_const_block_item()?)
} else if let Const::Yes(const_span) = self.parse_constness(case) {
// CONST ITEM
self.recover_const_mut(const_span);
@ -316,6 +341,7 @@ impl<'a> Parser<'a> {
return self.parse_item_kind(
attrs,
macros_allowed,
allow_const_block_items,
lo,
vis,
def,
@ -1068,8 +1094,13 @@ impl<'a> Parser<'a> {
fn_parse_mode: FnParseMode,
force_collect: ForceCollect,
) -> PResult<'a, Option<Option<Box<AssocItem>>>> {
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
|Item { attrs, id, span, vis, kind, tokens }| {
Ok(self
.parse_item_(
fn_parse_mode,
force_collect,
AllowConstBlockItems::DoesNotMatter, // due to `AssocItemKind::try_from` below
)?
.map(|Item { attrs, id, span, vis, kind, tokens }| {
let kind = match AssocItemKind::try_from(kind) {
Ok(kind) => kind,
Err(kind) => match kind {
@ -1096,8 +1127,7 @@ impl<'a> Parser<'a> {
},
};
Some(Box::new(Item { attrs, id, span, vis, kind, tokens }))
},
))
}))
}
/// Parses a `type` alias with the following grammar:
@ -1320,8 +1350,13 @@ impl<'a> Parser<'a> {
context: FnContext::Free,
req_body: false,
};
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
|Item { attrs, id, span, vis, kind, tokens }| {
Ok(self
.parse_item_(
fn_parse_mode,
force_collect,
AllowConstBlockItems::DoesNotMatter, // due to `ForeignItemKind::try_from` below
)?
.map(|Item { attrs, id, span, vis, kind, tokens }| {
let kind = match ForeignItemKind::try_from(kind) {
Ok(kind) => kind,
Err(kind) => match kind {
@ -1348,8 +1383,7 @@ impl<'a> Parser<'a> {
},
};
Some(Box::new(Item { attrs, id, span, vis, kind, tokens }))
},
))
}))
}
fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &'static str) -> Option<T> {
@ -1437,6 +1471,14 @@ impl<'a> Parser<'a> {
}
}
fn parse_const_block_item(&mut self) -> PResult<'a, ConstBlockItem> {
self.expect_keyword(exp!(Const))?;
let const_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::const_block_items, const_span);
let block = self.parse_block()?;
Ok(ConstBlockItem { id: DUMMY_NODE_ID, span: const_span.to(block.span), block })
}
/// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in
/// `mutability`.
///
@ -2394,7 +2436,10 @@ impl<'a> Parser<'a> {
{
let kw_token = self.token;
let kw_str = pprust::token_to_string(&kw_token);
let item = self.parse_item(ForceCollect::No)?;
let item = self.parse_item(
ForceCollect::No,
AllowConstBlockItems::DoesNotMatter, // self.token != kw::Const
)?;
let mut item = item.unwrap().span;
if self.token == token::Comma {
item = item.to(self.token.span);

View file

@ -145,6 +145,14 @@ pub enum ForceCollect {
No,
}
/// Whether to accept `const { ... }` as a shorthand for `const _: () = const { ... }`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AllowConstBlockItems {
Yes,
No,
DoesNotMatter,
}
/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`.
#[macro_export]
macro_rules! maybe_recover_from_interpolated_ty_qpath {

View file

@ -6,7 +6,9 @@ use rustc_span::{Ident, kw};
use crate::errors::UnexpectedNonterminal;
use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
use crate::parser::{FollowedByType, ForceCollect, ParseNtResult, Parser, PathStyle};
use crate::parser::{
AllowConstBlockItems, FollowedByType, ForceCollect, ParseNtResult, Parser, PathStyle,
};
impl<'a> Parser<'a> {
/// Checks whether a non-terminal may begin with a particular token.
@ -118,7 +120,9 @@ impl<'a> Parser<'a> {
match kind {
// Note that TT is treated differently to all the others.
NonterminalKind::TT => Ok(ParseNtResult::Tt(self.parse_token_tree())),
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
NonterminalKind::Item => match self
.parse_item(ForceCollect::Yes, AllowConstBlockItems::Yes)?
{
Some(item) => Ok(ParseNtResult::Item(item)),
None => Err(self.dcx().create_err(UnexpectedNonterminal::Item(self.token.span))),
},

View file

@ -20,8 +20,8 @@ use super::diagnostics::AttemptLocalParseRecovery;
use super::pat::{PatternLocation, RecoverComma};
use super::path::PathStyle;
use super::{
AttrWrapper, BlockMode, FnContext, FnParseMode, ForceCollect, Parser, Restrictions,
SemiColonMode, Trailing, UsePreAttrPos,
AllowConstBlockItems, AttrWrapper, BlockMode, FnContext, FnParseMode, ForceCollect, Parser,
Restrictions, SemiColonMode, Trailing, UsePreAttrPos,
};
use crate::errors::{self, MalformedLoopLabel};
use crate::exp;
@ -156,6 +156,7 @@ impl<'a> Parser<'a> {
true,
FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true },
force_collect,
AllowConstBlockItems::No,
)? {
self.mk_stmt(lo.to(item.span), StmtKind::Item(Box::new(item)))
} else if self.eat(exp!(Semi)) {

View file

@ -22,7 +22,7 @@ use rustc_span::{
};
use crate::lexer::StripTokens;
use crate::parser::{ForceCollect, Parser};
use crate::parser::{AllowConstBlockItems, ForceCollect, Parser};
use crate::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
fn psess() -> ParseSess {
@ -2233,7 +2233,7 @@ fn parse_item_from_source_str(
psess: &ParseSess,
) -> PResult<'_, Option<Box<ast::Item>>> {
unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing))
.parse_item(ForceCollect::No)
.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)
}
// Produces a `rustc_span::span`.
@ -2248,7 +2248,9 @@ fn string_to_expr(source_str: String) -> Box<ast::Expr> {
/// Parses a string, returns an item.
fn string_to_item(source_str: String) -> Option<Box<ast::Item>> {
with_error_checking_parse(source_str, &psess(), |p| p.parse_item(ForceCollect::No))
with_error_checking_parse(source_str, &psess(), |p| {
p.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)
})
}
#[test]

View file

@ -572,6 +572,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Use,
Static,
Const,
ConstBlock,
Fn,
Mod,
ForeignMod,

View file

@ -276,7 +276,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
ast::ItemKind::ExternCrate(..) => Target::ExternCrate,
ast::ItemKind::Use(_) => Target::Use,
ast::ItemKind::Static(_) => Target::Static,
ast::ItemKind::Const(_) => Target::Const,
ast::ItemKind::Const(_) | ast::ItemKind::ConstBlock(_) => Target::Const,
ast::ItemKind::Fn(_) | ast::ItemKind::Delegation(..) => Target::Fn,
ast::ItemKind::Mod(..) => Target::Mod,
ast::ItemKind::ForeignMod(_) => Target::ForeignFn,

View file

@ -4,6 +4,7 @@
// tidy-alphabetical-start
#![allow(unused_crate_dependencies)]
#![cfg_attr(feature = "rustc", feature(if_let_guard))]
// tidy-alphabetical-end
pub(crate) mod checks;

View file

@ -4,8 +4,8 @@ use std::iter::once;
use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
use rustc_arena::DroplessArena;
use rustc_hir::HirId;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId};
use rustc_index::{Idx, IndexVec};
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
@ -468,12 +468,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
fields = vec![];
arity = 0;
}
PatKind::Deref { subpattern } => {
PatKind::Deref { pin, subpattern } => {
fields = vec![self.lower_pat(subpattern).at_index(0)];
arity = 1;
ctor = match ty.pinned_ref() {
None if ty.is_ref() => Ref,
Some((inner_ty, _)) => {
ctor = match pin {
hir::Pinnedness::Not if ty.is_ref() => Ref,
hir::Pinnedness::Pinned if let Some((inner_ty, _)) = ty.pinned_ref() => {
self.internal_state.has_lowered_deref_pat.set(true);
DerefPattern(RevealedTy(inner_ty))
}

View file

@ -18,13 +18,13 @@ use rustc_middle::query::{
queries,
};
use rustc_middle::ty::TyCtxt;
use rustc_query_system::Value;
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState,
get_query_incr, get_query_non_incr,
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode,
QueryState, get_query_incr, get_query_non_incr,
};
use rustc_query_system::{HandleCycleError, Value};
use rustc_span::{ErrorGuaranteed, Span};
use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
@ -181,8 +181,8 @@ where
}
#[inline(always)]
fn handle_cycle_error(self) -> HandleCycleError {
self.dynamic.handle_cycle_error
fn cycle_error_handling(self) -> CycleErrorHandling {
self.dynamic.cycle_error_handling
}
#[inline(always)]

View file

@ -199,21 +199,21 @@ pub fn query_key_hash_verify_all<'tcx>(tcx: TyCtxt<'tcx>) {
}
}
macro_rules! handle_cycle_error {
macro_rules! cycle_error_handling {
([]) => {{
rustc_query_system::HandleCycleError::Error
rustc_query_system::query::CycleErrorHandling::Error
}};
([(cycle_fatal) $($rest:tt)*]) => {{
rustc_query_system::HandleCycleError::Fatal
rustc_query_system::query::CycleErrorHandling::Fatal
}};
([(cycle_stash) $($rest:tt)*]) => {{
rustc_query_system::HandleCycleError::Stash
rustc_query_system::query::CycleErrorHandling::Stash
}};
([(cycle_delay_bug) $($rest:tt)*]) => {{
rustc_query_system::HandleCycleError::DelayBug
rustc_query_system::query::CycleErrorHandling::DelayBug
}};
([$other:tt $($modifiers:tt)*]) => {
handle_cycle_error!([$($modifiers)*])
cycle_error_handling!([$($modifiers)*])
};
}
@ -618,7 +618,7 @@ macro_rules! define_queries {
name: stringify!($name),
eval_always: is_eval_always!([$($modifiers)*]),
dep_kind: dep_graph::dep_kinds::$name,
handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
cycle_error_handling: cycle_error_handling!([$($modifiers)*]),
query_state: std::mem::offset_of!(QueryStates<'tcx>, $name),
query_cache: std::mem::offset_of!(QueryCaches<'tcx>, $name),
cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key),

View file

@ -11,14 +11,6 @@ pub(crate) struct CycleStack {
pub desc: String,
}
#[derive(Copy, Clone)]
pub enum HandleCycleError {
Error,
Fatal,
DelayBug,
Stash,
}
#[derive(Subdiagnostic)]
pub(crate) enum StackCount {
#[note(query_system_cycle_stack_single)]

View file

@ -12,7 +12,7 @@ pub mod ich;
pub mod query;
mod values;
pub use error::{HandleCycleError, QueryOverflow, QueryOverflowNote};
pub use error::{QueryOverflow, QueryOverflowNote};
pub use values::Value;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

View file

@ -7,10 +7,9 @@ use rustc_data_structures::fingerprint::Fingerprint;
use rustc_span::ErrorGuaranteed;
use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex};
use crate::error::HandleCycleError;
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
use crate::query::{CycleError, DepNodeIndex, QueryContext, QueryState};
use crate::query::{CycleError, CycleErrorHandling, DepNodeIndex, QueryContext, QueryState};
pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
@ -67,7 +66,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
fn feedable(self) -> bool;
fn dep_kind(self) -> DepKind;
fn handle_cycle_error(self) -> HandleCycleError;
fn cycle_error_handling(self) -> CycleErrorHandling;
fn hash_result(self) -> HashResult<Self::Value>;
// Just here for convenience and checking that the key matches the kind, don't override this.

View file

@ -20,6 +20,18 @@ mod config;
mod job;
mod plumbing;
/// How a particular query deals with query cycle errors.
///
/// Inspected by the code that actually handles cycle errors, to decide what
/// approach to use.
#[derive(Copy, Clone)]
pub enum CycleErrorHandling {
Error,
Fatal,
DelayBug,
Stash,
}
/// Description of a frame in the query stack.
///
/// This is mostly used in case of cycles for error reporting.

View file

@ -19,12 +19,13 @@ use rustc_span::{DUMMY_SP, Span};
use tracing::instrument;
use super::QueryConfig;
use crate::HandleCycleError;
use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams};
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle};
use crate::query::{QueryContext, QueryMap, QueryStackFrame, SerializedDepNodeIndex};
use crate::query::{
CycleErrorHandling, QueryContext, QueryMap, QueryStackFrame, SerializedDepNodeIndex,
};
#[inline]
fn equivalent_key<K: Eq, V>(k: &K) -> impl Fn(&(K, V)) -> bool + '_ {
@ -142,22 +143,21 @@ where
Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
use HandleCycleError::*;
match query.handle_cycle_error() {
Error => {
match query.cycle_error_handling() {
CycleErrorHandling::Error => {
let guar = error.emit();
query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar)
}
Fatal => {
CycleErrorHandling::Fatal => {
error.emit();
qcx.dep_context().sess().dcx().abort_if_errors();
unreachable!()
}
DelayBug => {
CycleErrorHandling::DelayBug => {
let guar = error.delay_as_bug();
query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar)
}
Stash => {
CycleErrorHandling::Stash => {
let guar = if let Some(root) = cycle_error.cycle.first()
&& let Some(span) = root.query.span
{

View file

@ -959,7 +959,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
// These items do not add names to modules.
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
ItemKind::Impl { .. }
| ItemKind::ForeignMod(..)
| ItemKind::GlobalAsm(..)
| ItemKind::ConstBlock(..) => {}
ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
unreachable!()

View file

@ -131,7 +131,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
mutability: s.mutability,
nested: false,
},
ItemKind::Const(..) => DefKind::Const,
ItemKind::Const(..) | ItemKind::ConstBlock(..) => DefKind::Const,
ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
ItemKind::MacroDef(ident, def) => {
let edition = i.span.edition();

View file

@ -275,6 +275,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx>
| ast::ItemKind::Use(..)
| ast::ItemKind::Static(..)
| ast::ItemKind::Const(..)
| ast::ItemKind::ConstBlock(..)
| ast::ItemKind::GlobalAsm(..)
| ast::ItemKind::TyAlias(..)
| ast::ItemKind::TraitAlias(..)

View file

@ -2727,8 +2727,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
debug!("(resolving item) resolving {:?} ({:?})", item.kind.ident(), item.kind);
let def_kind = self.r.local_def_kind(item.id);
match item.kind {
ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
match &item.kind {
ItemKind::TyAlias(box TyAlias { generics, .. }) => {
self.with_generic_param_rib(
&generics.params,
RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
@ -2739,7 +2739,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
);
}
ItemKind::Fn(box Fn { ref generics, ref define_opaque, .. }) => {
ItemKind::Fn(box Fn { generics, define_opaque, .. }) => {
self.with_generic_param_rib(
&generics.params,
RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
@ -2751,19 +2751,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.resolve_define_opaques(define_opaque);
}
ItemKind::Enum(_, ref generics, _)
| ItemKind::Struct(_, ref generics, _)
| ItemKind::Union(_, ref generics, _) => {
ItemKind::Enum(_, generics, _)
| ItemKind::Struct(_, generics, _)
| ItemKind::Union(_, generics, _) => {
self.resolve_adt(item, generics);
}
ItemKind::Impl(Impl {
ref generics,
ref of_trait,
ref self_ty,
items: ref impl_items,
..
}) => {
ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, .. }) => {
self.diag_metadata.current_impl_items = Some(impl_items);
self.resolve_implementation(
&item.attrs,
@ -2776,7 +2770,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.diag_metadata.current_impl_items = None;
}
ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
ItemKind::Trait(box Trait { generics, bounds, items, .. }) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(
&generics.params,
@ -2795,7 +2789,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
);
}
ItemKind::TraitAlias(box TraitAlias { ref generics, ref bounds, .. }) => {
ItemKind::TraitAlias(box TraitAlias { generics, bounds, .. }) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(
&generics.params,
@ -2835,13 +2829,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.parent_scope.module = orig_module;
}
ItemKind::Static(box ast::StaticItem {
ident,
ref ty,
ref expr,
ref define_opaque,
..
}) => {
ItemKind::Static(box ast::StaticItem { ident, ty, expr, define_opaque, .. }) => {
self.with_static_rib(def_kind, |this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
this.visit_ty(ty);
@ -2849,7 +2837,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
if let Some(expr) = expr {
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
this.resolve_static_body(expr, Some((ident, ConstantItemKind::Static)));
this.resolve_static_body(expr, Some((*ident, ConstantItemKind::Static)));
}
});
self.resolve_define_opaques(define_opaque);
@ -2857,11 +2845,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
ItemKind::Const(box ast::ConstItem {
ident,
ref generics,
ref ty,
ref rhs,
ref define_opaque,
..
generics,
ty,
rhs,
define_opaque,
defaultness: _,
}) => {
let is_type_const = attr::contains_name(&item.attrs, sym::type_const);
self.with_generic_param_rib(
@ -2903,15 +2891,36 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
if let Some(rhs) = rhs {
this.resolve_const_item_rhs(
rhs,
Some((ident, ConstantItemKind::Const)),
Some((*ident, ConstantItemKind::Const)),
);
}
},
);
self.resolve_define_opaques(define_opaque);
}
ItemKind::ConstBlock(ConstBlockItem { id: _, span: _, block }) => self
.with_generic_param_rib(
&[],
RibKind::Item(HasGenericParams::No, def_kind),
item.id,
LifetimeBinderKind::ConstItem,
DUMMY_SP,
|this| {
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Infer),
|this| {
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
Some((ConstBlockItem::IDENT, ConstantItemKind::Const)),
|this| this.resolve_labeled_block(None, block.id, block),
)
},
);
},
),
ItemKind::Use(ref use_tree) => {
ItemKind::Use(use_tree) => {
let maybe_exported = match use_tree.kind {
UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id),
UseTreeKind::Nested { .. } => MaybeExported::NestedUse(&item.vis),
@ -2921,7 +2930,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.future_proof_import(use_tree);
}
ItemKind::MacroDef(_, ref macro_def) => {
ItemKind::MacroDef(_, macro_def) => {
// Maintain macro_rules scopes in the same way as during early resolution
// for diagnostics and doc links.
if macro_def.macro_rules {
@ -2945,7 +2954,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
visit::walk_item(self, item);
}
ItemKind::Delegation(ref delegation) => {
ItemKind::Delegation(delegation) => {
let span = delegation.path.segments.last().unwrap().ident.span;
self.with_generic_param_rib(
&[],
@ -5477,6 +5486,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
ItemKind::Mod(..)
| ItemKind::Static(..)
| ItemKind::ConstBlock(..)
| ItemKind::Use(..)
| ItemKind::ExternCrate(..)
| ItemKind::MacroDef(..)

View file

@ -2426,6 +2426,9 @@ options! {
`=skip-entry`
`=skip-exit`
Multiple options can be combined with commas."),
large_data_threshold: Option<u64> = (None, parse_opt_number, [TRACKED],
"set the threshold for objects to be stored in a \"large data\" section \
(only effective with -Ccode-model=medium, default: 65536)"),
layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
"seed layout randomization"),
link_directives: bool = (true, parse_bool, [TRACKED],

View file

@ -731,6 +731,7 @@ symbols! {
console,
const_allocate,
const_async_blocks,
const_block_items,
const_closures,
const_compare_raw_pointers,
const_constructor,
@ -2140,6 +2141,7 @@ symbols! {
simd_shr,
simd_shuffle,
simd_shuffle_const_generic,
simd_splat,
simd_sub,
simd_trunc,
simd_with_exposed_provenance,

View file

@ -47,7 +47,7 @@ impl RiscVInlineAsmRegClass {
types! { _: I8, I16, I32, F16, F32; }
}
}
// FIXME(f16_f128): Add `q: F128;` once LLVM support the `Q` extension.
// FIXME(f128): Add `q: F128;` once LLVM support the `Q` extension.
Self::freg => types! { f: F16, F32; d: F64; },
Self::vreg => &[],
}

View file

@ -1596,8 +1596,11 @@ supported_targets! {
("armebv7r-none-eabi", armebv7r_none_eabi),
("armebv7r-none-eabihf", armebv7r_none_eabihf),
("armv7r-none-eabi", armv7r_none_eabi),
("thumbv7r-none-eabi", thumbv7r_none_eabi),
("armv7r-none-eabihf", armv7r_none_eabihf),
("thumbv7r-none-eabihf", thumbv7r_none_eabihf),
("armv8r-none-eabihf", armv8r_none_eabihf),
("thumbv8r-none-eabihf", thumbv8r_none_eabihf),
("armv7-rtems-eabihf", armv7_rtems_eabihf),
@ -1649,7 +1652,9 @@ supported_targets! {
("thumbv8m.main-none-eabihf", thumbv8m_main_none_eabihf),
("armv7a-none-eabi", armv7a_none_eabi),
("thumbv7a-none-eabi", thumbv7a_none_eabi),
("armv7a-none-eabihf", armv7a_none_eabihf),
("thumbv7a-none-eabihf", thumbv7a_none_eabihf),
("armv7a-nuttx-eabi", armv7a_nuttx_eabi),
("armv7a-nuttx-eabihf", armv7a_nuttx_eabihf),
("armv7a-vex-v5", armv7a_vex_v5),
@ -1741,10 +1746,14 @@ supported_targets! {
("mipsel-unknown-none", mipsel_unknown_none),
("mips-mti-none-elf", mips_mti_none_elf),
("mipsel-mti-none-elf", mipsel_mti_none_elf),
("thumbv4t-none-eabi", thumbv4t_none_eabi),
("armv4t-none-eabi", armv4t_none_eabi),
("thumbv5te-none-eabi", thumbv5te_none_eabi),
("armv5te-none-eabi", armv5te_none_eabi),
("armv6-none-eabi", armv6_none_eabi),
("armv6-none-eabihf", armv6_none_eabihf),
("thumbv4t-none-eabi", thumbv4t_none_eabi),
("thumbv5te-none-eabi", thumbv5te_none_eabi),
("thumbv6-none-eabi", thumbv6_none_eabi),
("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),

View file

@ -1,4 +1,4 @@
//! Targets the ARMv4T, with code as `a32` code by default.
//! Targets the ARMv4T architecture, with `a32` code by default.
//!
//! Primarily of use for the GBA, but usable with other devices too.
//!

View file

@ -1,4 +1,4 @@
//! Targets the ARMv5TE, with code as `a32` code by default.
//! Targets the ARMv5TE architecture, with `a32` code by default.
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};

View file

@ -0,0 +1,29 @@
//! Targets the ARMv6K architecture, with `a32` code by default.
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
llvm_target: "armv6-none-eabi".into(),
metadata: TargetMetadata {
description: Some("Bare ARMv6 soft-float".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
arch: Arch::Arm,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
options: TargetOptions {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",],
features: "+soft-float,+strict-align,+v6k".into(),
atomic_cas: true,
has_thumb_interworking: true,
// LDREXD/STREXD available as of ARMv6K
max_atomic_width: Some(64),
..base::arm_none::opts()
},
}
}

View file

@ -0,0 +1,29 @@
//! Targets the ARMv6K architecture, with `a32` code by default, and hard-float ABI
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
llvm_target: "armv6-none-eabihf".into(),
metadata: TargetMetadata {
description: Some("Bare ARMv6 hard-float".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
arch: Arch::Arm,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
options: TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",],
features: "+strict-align,+v6k,+vfp2,-d32".into(),
atomic_cas: true,
has_thumb_interworking: true,
// LDREXD/STREXD available as of ARMv6K
max_atomic_width: Some(64),
..base::arm_none::opts()
},
}
}

View file

@ -1,40 +1,8 @@
// Generic ARMv7-A target for bare-metal code - floating point disabled
//
// This is basically the `armv7-unknown-linux-gnueabi` target with some changes
// (listed below) to bring it closer to the bare-metal `thumb` & `aarch64`
// targets:
//
// - `TargetOptions.features`: added `+strict-align`. rationale: unaligned
// memory access is disabled on boot on these cores
// - linker changed to LLD. rationale: C is not strictly needed to build
// bare-metal binaries (the `gcc` linker has the advantage that it knows where C
// libraries and crt*.o are but it's not much of an advantage here); LLD is also
// faster
// - `panic_strategy` set to `abort`. rationale: matches `thumb` targets
// - `relocation-model` set to `static`; also no PIE, no relro and no dynamic
// linking. rationale: matches `thumb` targets
// Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A)
use crate::spec::{
Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
TargetOptions,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(),
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(64),
panic_strategy: PanicStrategy::Abort,
emit_debug_gdb_scripts: false,
c_enum_min_bits: Some(8),
has_thumb_interworking: true,
..Default::default()
};
Target {
llvm_target: "armv7a-none-eabi".into(),
metadata: TargetMetadata {
@ -46,6 +14,13 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: opts,
options: TargetOptions {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
features: "+soft-float,-neon,+strict-align".into(),
max_atomic_width: Some(64),
has_thumb_interworking: true,
..base::arm_none::opts()
},
}
}

View file

@ -1,32 +1,8 @@
// Generic ARMv7-A target for bare-metal code - floating point enabled (assumes
// FPU is present and emits FPU instructions)
//
// This is basically the `armv7-unknown-linux-gnueabihf` target with some
// changes (list in `armv7a_none_eabi.rs`) to bring it closer to the bare-metal
// `thumb` & `aarch64` targets.
// Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A)
use crate::spec::{
Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
TargetOptions,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
let opts = TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+vfp3d16,+thumb2,-neon,+strict-align".into(),
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(64),
panic_strategy: PanicStrategy::Abort,
emit_debug_gdb_scripts: false,
// GCC defaults to 8 for arm-none here.
c_enum_min_bits: Some(8),
has_thumb_interworking: true,
..Default::default()
};
Target {
llvm_target: "armv7a-none-eabihf".into(),
metadata: TargetMetadata {
@ -38,6 +14,13 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: opts,
options: TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
features: "+vfp3d16,-neon,+strict-align".into(),
max_atomic_width: Some(64),
has_thumb_interworking: true,
..base::arm_none::opts()
},
}
}

View file

@ -1,15 +1,12 @@
// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
use crate::spec::{
Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
TargetOptions,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
llvm_target: "armv7r-none-eabi".into(),
metadata: TargetMetadata {
description: Some("Armv7-R".into()),
description: Some("Bare Armv7-R".into()),
tier: Some(2),
host_tools: Some(false),
std: Some(false),
@ -17,20 +14,12 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: TargetOptions {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC defaults to 8 for arm-none here.
c_enum_min_bits: Some(8),
has_thumb_interworking: true,
..Default::default()
..base::arm_none::opts()
},
}
}

View file

@ -1,15 +1,12 @@
// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
use crate::spec::{
Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
TargetOptions,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
llvm_target: "armv7r-none-eabihf".into(),
metadata: TargetMetadata {
description: Some("Armv7-R, hardfloat".into()),
description: Some("Bare Armv7-R, hardfloat".into()),
tier: Some(2),
host_tools: Some(false),
std: Some(false),
@ -17,21 +14,13 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
features: "+vfp3d16".into(),
max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC defaults to 8 for arm-none here.
c_enum_min_bits: Some(8),
has_thumb_interworking: true,
..Default::default()
..base::arm_none::opts()
},
}
}

View file

@ -1,9 +1,6 @@
// Targets the Little-endian Cortex-R52 processor (ARMv8-R)
use crate::spec::{
Abi, Arch, Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata,
TargetOptions,
};
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
@ -21,10 +18,6 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
// Armv8-R requires a minimum set of floating-point features equivalent to:
// fp-armv8, SP-only, with 16 DP (32 SP) registers
// LLVM defines Armv8-R to include these features automatically.
@ -36,11 +29,8 @@ pub(crate) fn target() -> Target {
// Arm Cortex-R52 Processor Technical Reference Manual
// - Chapter 15 Advanced SIMD and floating-point support
max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC defaults to 8 for arm-none here.
c_enum_min_bits: Some(8),
has_thumb_interworking: true,
..Default::default()
..base::arm_none::opts()
},
}
}

View file

@ -17,8 +17,8 @@ pub(crate) fn target() -> Target {
llvm_target: "powerpc64-unknown-linux-musl".into(),
metadata: TargetMetadata {
description: Some("64-bit PowerPC Linux with musl 1.2.5".into()),
tier: Some(3),
host_tools: Some(false),
tier: Some(2),
host_tools: Some(true),
std: Some(true),
},
pointer_width: 64,

View file

@ -1,4 +1,4 @@
//! Targets the ARMv4T, with code as `t32` code by default.
//! Targets the ARMv4T architecture, with `t32` code by default.
//!
//! Primarily of use for the GBA, but usable with other devices too.
//!

View file

@ -1,4 +1,4 @@
//! Targets the ARMv5TE, with code as `t32` code by default.
//! Targets the ARMv5TE architecture, with `t32` code by default.
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};

View file

@ -0,0 +1,30 @@
//! Targets the ARMv6K architecture, with `t32` code by default.
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base, cvs};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv6-none-eabi".into(),
metadata: TargetMetadata {
description: Some("Thumb-mode Bare ARMv6 soft-float".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
arch: Arch::Arm,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
options: TargetOptions {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
asm_args: cvs!["-mthumb-interwork", "-march=armv6", "-mlittle-endian",],
features: "+soft-float,+strict-align,+v6k".into(),
// CAS atomics are implemented in LLVM on this target using __sync* functions,
// which were added to compiler-builtins in https://github.com/rust-lang/compiler-builtins/pull/1050
atomic_cas: true,
has_thumb_interworking: true,
max_atomic_width: Some(32),
..base::arm_none::opts()
},
}
}

View file

@ -0,0 +1,26 @@
// Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A)
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv7a-none-eabi".into(),
metadata: TargetMetadata {
description: Some("Thumb-mode Bare Armv7-A".into()),
tier: Some(2),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: TargetOptions {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
features: "+soft-float,-neon,+strict-align".into(),
max_atomic_width: Some(64),
has_thumb_interworking: true,
..base::arm_none::opts()
},
}
}

View file

@ -0,0 +1,26 @@
// Targets the Little-endian Cortex-A8 (and similar) processors (ARMv7-A)
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv7a-none-eabihf".into(),
metadata: TargetMetadata {
description: Some("Thumb-mode Bare Armv7-A, hardfloat".into()),
tier: Some(2),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
features: "+vfp3d16,-neon,+strict-align".into(),
max_atomic_width: Some(64),
has_thumb_interworking: true,
..base::arm_none::opts()
},
}
}

View file

@ -0,0 +1,25 @@
// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv7r-none-eabi".into(),
metadata: TargetMetadata {
description: Some("Thumb-mode Bare Armv7-R".into()),
tier: Some(2),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: TargetOptions {
abi: Abi::Eabi,
llvm_floatabi: Some(FloatAbi::Soft),
max_atomic_width: Some(64),
has_thumb_interworking: true,
..base::arm_none::opts()
},
}
}

View file

@ -0,0 +1,26 @@
// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv7r-none-eabihf".into(),
metadata: TargetMetadata {
description: Some("Thumb-mode Bare Armv7-R, hardfloat".into()),
tier: Some(2),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
features: "+vfp3d16".into(),
max_atomic_width: Some(64),
has_thumb_interworking: true,
..base::arm_none::opts()
},
}
}

View file

@ -0,0 +1,36 @@
// Targets the Little-endian Cortex-R52 processor (ARMv8-R)
use crate::spec::{Abi, Arch, FloatAbi, Target, TargetMetadata, TargetOptions, base};
pub(crate) fn target() -> Target {
Target {
llvm_target: "thumbv8r-none-eabihf".into(),
metadata: TargetMetadata {
description: Some("Thumb-mode Bare Armv8-R, hardfloat".into()),
tier: Some(2),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: Arch::Arm,
options: TargetOptions {
abi: Abi::EabiHf,
llvm_floatabi: Some(FloatAbi::Hard),
// Armv8-R requires a minimum set of floating-point features equivalent to:
// fp-armv8, SP-only, with 16 DP (32 SP) registers
// LLVM defines Armv8-R to include these features automatically.
//
// The Cortex-R52 supports these default features and optionally includes:
// neon-fp-armv8, SP+DP, with 32 DP registers
//
// Reference:
// Arm Cortex-R52 Processor Technical Reference Manual
// - Chapter 15 Advanced SIMD and floating-point support
max_atomic_width: Some(64),
has_thumb_interworking: true,
..base::arm_none::opts()
},
}
}

View file

@ -492,7 +492,22 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
("hvx", Unstable(sym::hexagon_target_feature), &[]),
("hvx-ieee-fp", Unstable(sym::hexagon_target_feature), &["hvx"]),
("hvx-length64b", Unstable(sym::hexagon_target_feature), &["hvx"]),
("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
("hvx-qfloat", Unstable(sym::hexagon_target_feature), &["hvx"]),
("hvxv60", Unstable(sym::hexagon_target_feature), &["hvx"]),
("hvxv62", Unstable(sym::hexagon_target_feature), &["hvxv60"]),
("hvxv65", Unstable(sym::hexagon_target_feature), &["hvxv62"]),
("hvxv66", Unstable(sym::hexagon_target_feature), &["hvxv65", "zreg"]),
("hvxv67", Unstable(sym::hexagon_target_feature), &["hvxv66"]),
("hvxv68", Unstable(sym::hexagon_target_feature), &["hvxv67"]),
("hvxv69", Unstable(sym::hexagon_target_feature), &["hvxv68"]),
("hvxv71", Unstable(sym::hexagon_target_feature), &["hvxv69"]),
("hvxv73", Unstable(sym::hexagon_target_feature), &["hvxv71"]),
("hvxv75", Unstable(sym::hexagon_target_feature), &["hvxv73"]),
("hvxv79", Unstable(sym::hexagon_target_feature), &["hvxv75"]),
("zreg", Unstable(sym::hexagon_target_feature), &[]),
// tidy-alphabetical-end
];
@ -949,7 +964,7 @@ const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'stat
&[/*(64, "vis")*/];
const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
&[(512, "hvx-length64b"), (1024, "hvx-length128b")];
const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "msa")];
const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =

View file

@ -865,9 +865,13 @@ const fn handle_error(e: TryReserveError) -> ! {
#[inline]
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
const fn layout_array(cap: usize, elem_layout: Layout) -> Result<Layout, TryReserveError> {
// This is only used with `elem_layout`s which are those of real rust types,
// which lets us use the much-simpler `repeat_packed`.
debug_assert!(elem_layout.size() == elem_layout.pad_to_align().size());
// FIXME(const-hack) return to using `map` and `map_err` once `const_closures` is implemented
match elem_layout.repeat(cap) {
Ok((layout, _pad)) => Ok(layout),
match elem_layout.repeat_packed(cap) {
Ok(layout) => Ok(layout),
Err(_) => Err(CapacityOverflow.into()),
}
}

View file

@ -118,12 +118,12 @@ use crate::{cmp, ptr};
///
/// # Re-entrance
///
/// When implementing a global allocator one has to be careful not to create an infinitely recursive
/// When implementing a global allocator, one has to be careful not to create an infinitely recursive
/// implementation by accident, as many constructs in the Rust standard library may allocate in
/// their implementation. For example, on some platforms [`std::sync::Mutex`] may allocate, so using
/// their implementation. For example, on some platforms, [`std::sync::Mutex`] may allocate, so using
/// it is highly problematic in a global allocator.
///
/// Generally speaking for this reason one should stick to library features available through
/// For this reason, one should generally stick to library features available through
/// [`core`], and avoid using [`std`] in a global allocator. A few features from [`std`] are
/// guaranteed to not use `#[global_allocator]` to allocate:
///

View file

@ -1,5 +1,7 @@
//! impl bool {}
use crate::marker::Destruct;
impl bool {
/// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html),
/// or `None` otherwise.
@ -29,8 +31,9 @@ impl bool {
/// assert_eq!(a, 2);
/// ```
#[stable(feature = "bool_to_option", since = "1.62.0")]
#[rustc_const_unstable(feature = "const_bool", issue = "151531")]
#[inline]
pub fn then_some<T>(self, t: T) -> Option<T> {
pub const fn then_some<T: [const] Destruct>(self, t: T) -> Option<T> {
if self { Some(t) } else { None }
}
@ -57,8 +60,9 @@ impl bool {
#[doc(alias = "then_with")]
#[stable(feature = "lazy_bool_to_option", since = "1.50.0")]
#[rustc_diagnostic_item = "bool_then"]
#[rustc_const_unstable(feature = "const_bool", issue = "151531")]
#[inline]
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
pub const fn then<T, F: [const] FnOnce() -> T + [const] Destruct>(self, f: F) -> Option<T> {
if self { Some(f()) } else { None }
}
@ -94,8 +98,9 @@ impl bool {
/// assert_eq!(a, 2);
/// ```
#[unstable(feature = "bool_to_result", issue = "142748")]
#[rustc_const_unstable(feature = "const_bool", issue = "151531")]
#[inline]
pub fn ok_or<E>(self, err: E) -> Result<(), E> {
pub const fn ok_or<E: [const] Destruct>(self, err: E) -> Result<(), E> {
if self { Ok(()) } else { Err(err) }
}
@ -124,8 +129,12 @@ impl bool {
/// assert_eq!(a, 1);
/// ```
#[unstable(feature = "bool_to_result", issue = "142748")]
#[rustc_const_unstable(feature = "const_bool", issue = "151531")]
#[inline]
pub fn ok_or_else<E, F: FnOnce() -> E>(self, f: F) -> Result<(), E> {
pub const fn ok_or_else<E, F: [const] FnOnce() -> E + [const] Destruct>(
self,
f: F,
) -> Result<(), E> {
if self { Ok(()) } else { Err(f()) }
}
}

View file

@ -154,7 +154,7 @@ impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.2
// * 53 bits in f64
// * 113 bits in f128
// Lossy float conversions are not implemented at this time.
// FIXME(f16_f128): The `f16`/`f128` impls `#[stable]` attributes should be changed to reference
// FIXME(f16,f128): The `f16`/`f128` impls `#[stable]` attributes should be changed to reference
// `f16`/`f128` when they are stabilised (trait impls have to have a `#[stable]` attribute, but none
// of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable).
@ -168,7 +168,7 @@ impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0"
impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised.
// FIXME(f128): This impl would allow using `f128` on stable before it is stabilised.
// impl_from!(i64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// unsigned integer -> float
@ -181,11 +181,11 @@ impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0"
impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised.
// FIXME(f128): This impl would allow using `f128` on stable before it is stabilised.
// impl_from!(u64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// float -> float
// FIXME(f16_f128): adding additional `From<{float}>` impls to `f32` breaks inference. See
// FIXME(f16,f128): adding additional `From<{float}>` impls to `f32` breaks inference. See
// <https://github.com/rust-lang/rust/issues/123831>
impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);

View file

@ -236,7 +236,7 @@ floating! { f32 f64 }
#[cfg(target_has_reliable_f16)]
floating! { f16 }
// FIXME(f16_f128): A fallback is used when the backend+target does not support f16 well, in order
// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order
// to avoid ICEs.
#[cfg(not(target_has_reliable_f16))]

View file

@ -292,9 +292,18 @@ pub fn spin_loop() {
// SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) }
}
all(target_arch = "arm", target_feature = "v6") => {
// SAFETY: the `cfg` attr ensures that we only execute this on arm targets
// with support for the v6 feature.
all(
target_arch = "arm",
any(
all(target_feature = "v6k", not(target_feature = "thumb-mode")),
target_feature = "v6t2",
all(target_feature = "v6", target_feature = "mclass"),
)
) => {
// SAFETY: the `cfg` attr ensures that we only execute this on arm
// targets with support for the this feature. On ARMv6 in Thumb
// mode, T2 is required (see Arm DDI0406C Section A8.8.427),
// otherwise ARMv6-M or ARMv6K is enough
unsafe { crate::arch::arm::__yield() }
}
target_arch = "loongarch32" => crate::arch::loongarch32::ibar::<0>(),

View file

@ -52,6 +52,13 @@ pub const unsafe fn simd_insert_dyn<T, U>(x: T, idx: u32, val: U) -> T;
#[rustc_intrinsic]
pub const unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U;
/// Creates a vector where every lane has the provided value.
///
/// `T` must be a vector with element type `U`.
#[rustc_nounwind]
#[rustc_intrinsic]
pub const unsafe fn simd_splat<T, U>(value: U) -> T;
/// Adds two simd vectors elementwise.
///
/// `T` must be a vector of integers or floats.

View file

@ -179,7 +179,7 @@ from_str_float_impl!(f16);
from_str_float_impl!(f32);
from_str_float_impl!(f64);
// FIXME(f16_f128): A fallback is used when the backend+target does not support f16 well, in order
// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order
// to avoid ICEs.
#[cfg(not(target_has_reliable_f16))]

View file

@ -137,10 +137,8 @@ pub mod consts {
pub const LN_10: f128 = 2.30258509299404568401799145468436420760110148862877297603333_f128;
}
#[doc(test(attr(feature(cfg_target_has_reliable_f16_f128), allow(internal_features))))]
impl f128 {
// FIXME(f16_f128): almost all methods in this `impl` are missing examples and a const
// implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE.
/// The radix or base of the internal representation of `f128`.
#[unstable(feature = "f128", issue = "116909")]
pub const RADIX: u32 = 2;
@ -277,8 +275,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `unordtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let nan = f128::NAN;
/// let f = 7.0_f128;
@ -300,8 +297,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let f = 7.0f128;
/// let inf = f128::INFINITY;
@ -326,8 +322,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `lttf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let f = 7.0f128;
/// let inf: f128 = f128::INFINITY;
@ -355,8 +350,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128
/// let max = f128::MAX;
@ -386,8 +380,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128
/// let max = f128::MAX;
@ -419,8 +412,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// use std::num::FpCategory;
///
@ -514,8 +506,7 @@ impl f128 {
///
/// ```rust
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// // f128::EPSILON is the difference between 1.0 and the next number up.
/// assert_eq!(1.0f128.next_up(), 1.0 + f128::EPSILON);
@ -569,8 +560,7 @@ impl f128 {
///
/// ```rust
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let x = 1.0f128;
/// // Clamp value into range [0, 1).
@ -613,8 +603,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let x = 2.0_f128;
/// let abs_difference = (x.recip() - (1.0 / x)).abs();
@ -640,8 +629,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let angle = std::f128::consts::PI;
///
@ -671,8 +659,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let angle = 180.0f128;
///
@ -706,8 +693,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // Using aarch64 because `reliable_f128_math` is needed
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128_math)] {
///
/// let x = 1.0f128;
/// let y = 2.0f128;
@ -738,8 +724,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // Using aarch64 because `reliable_f128_math` is needed
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128_math)] {
///
/// let x = 1.0f128;
/// let y = 2.0f128;
@ -771,8 +756,7 @@ impl f128 {
/// ```
/// #![feature(f128)]
/// #![feature(float_minimum_maximum)]
/// # // Using aarch64 because `reliable_f128_math` is needed
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128_math)] {
///
/// let x = 1.0f128;
/// let y = 2.0f128;
@ -804,8 +788,7 @@ impl f128 {
/// ```
/// #![feature(f128)]
/// #![feature(float_minimum_maximum)]
/// # // Using aarch64 because `reliable_f128_math` is needed
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128_math)] {
///
/// let x = 1.0f128;
/// let y = 2.0f128;
@ -831,8 +814,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // Using aarch64 because `reliable_f128_math` is needed
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// assert_eq!(1f128.midpoint(4.0), 2.5);
/// assert_eq!((-5.5f128).midpoint(8.0), 1.25);
@ -862,8 +844,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `float*itf` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let value = 4.6_f128;
/// let rounded = unsafe { value.to_int_unchecked::<u16>() };
@ -906,10 +887,11 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # #[cfg(target_has_reliable_f128)] {
///
/// # // FIXME(f16_f128): enable this once const casting works
/// # // assert_ne!((1f128).to_bits(), 1f128 as u128); // to_bits() is not casting!
/// assert_ne!((1f128).to_bits(), 1f128 as u128); // to_bits() is not casting!
/// assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000);
/// # }
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
@ -952,8 +934,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let v = f128::from_bits(0x40029000000000000000000000000000);
/// assert_eq!(v, 12.5);
@ -1064,8 +1045,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let value = f128::from_be_bytes(
/// [0x40, 0x02, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -1090,8 +1070,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let value = f128::from_le_bytes(
/// [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -1123,8 +1102,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `eqtf2` is available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let value = f128::from_ne_bytes(if cfg!(target_endian = "big") {
/// [0x40, 0x02, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -1257,8 +1235,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # // FIXME(f16_f128): remove when `{eq,gt,unord}tf` are available
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// assert!((-3.0f128).clamp(-2.0, 1.0) == -2.0);
/// assert!((0.0f128).clamp(-2.0, 1.0) == 0.0);
@ -1333,7 +1310,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let x = 3.5_f128;
/// let y = -3.5_f128;
@ -1349,9 +1326,7 @@ impl f128 {
#[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub const fn abs(self) -> Self {
// FIXME(f16_f128): replace with `intrinsics::fabsf128` when available
// We don't do this now because LLVM has lowering bugs for f128 math.
Self::from_bits(self.to_bits() & !(1 << 127))
intrinsics::fabsf128(self)
}
/// Returns a number that represents the sign of `self`.
@ -1364,7 +1339,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let f = 3.5_f128;
///
@ -1400,7 +1375,7 @@ impl f128 {
///
/// ```
/// #![feature(f128)]
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
/// # #[cfg(target_has_reliable_f128)] {
///
/// let f = 3.5_f128;
///
@ -1477,8 +1452,6 @@ impl f128 {
}
// Functions in this module fall into `core_float_math`
// FIXME(f16_f128): all doctests must be gated to platforms that have `long double` === `_Float128`
// due to https://github.com/llvm/llvm-project/issues/44744. aarch64 linux matches this.
// #[unstable(feature = "core_float_math", issue = "137578")]
#[cfg(not(test))]
#[doc(test(attr(feature(cfg_target_has_reliable_f16_f128), expect(internal_features))))]

View file

@ -134,9 +134,6 @@ pub mod consts {
#[doc(test(attr(feature(cfg_target_has_reliable_f16_f128), allow(internal_features))))]
impl f16 {
// FIXME(f16_f128): almost all methods in this `impl` are missing examples and a const
// implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE.
/// The radix or base of the internal representation of `f16`.
#[unstable(feature = "f16", issue = "116909")]
pub const RADIX: u32 = 2;
@ -887,8 +884,7 @@ impl f16 {
/// #![feature(f16)]
/// # #[cfg(target_has_reliable_f16)] {
///
/// # // FIXME(f16_f128): enable this once const casting works
/// # // assert_ne!((1f16).to_bits(), 1f16 as u128); // to_bits() is not casting!
/// assert_ne!((1f16).to_bits(), 1f16 as u16); // to_bits() is not casting!
/// assert_eq!((12.5f16).to_bits(), 0x4a40);
/// # }
/// ```

View file

@ -3,10 +3,7 @@
use core::ascii::EscapeDefault;
use crate::fmt::{self, Write};
#[cfg(not(any(
all(target_arch = "x86_64", target_feature = "sse2"),
all(target_arch = "loongarch64", target_feature = "lsx")
)))]
#[cfg(not(all(target_arch = "loongarch64", target_feature = "lsx")))]
use crate::intrinsics::const_eval_select;
use crate::{ascii, iter, ops};
@ -463,19 +460,101 @@ const fn is_ascii(s: &[u8]) -> bool {
)
}
/// ASCII test optimized to use the `pmovmskb` instruction on `x86-64` and the
/// `vmskltz.b` instruction on `loongarch64`.
/// Chunk size for vectorized ASCII checking (two 16-byte SSE registers).
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
const CHUNK_SIZE: usize = 32;
/// SSE2 implementation using `_mm_movemask_epi8` (compiles to `pmovmskb`) to
/// avoid LLVM's broken AVX-512 auto-vectorization of counting loops.
///
/// FIXME(llvm#176906): Remove this workaround once LLVM generates efficient code.
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
fn is_ascii_sse2(bytes: &[u8]) -> bool {
use crate::arch::x86_64::{__m128i, _mm_loadu_si128, _mm_movemask_epi8, _mm_or_si128};
let mut i = 0;
while i + CHUNK_SIZE <= bytes.len() {
// SAFETY: We have verified that `i + CHUNK_SIZE <= bytes.len()`.
let ptr = unsafe { bytes.as_ptr().add(i) };
// Load two 16-byte chunks and combine them.
// SAFETY: We verified `i + 32 <= len`, so ptr is valid for 32 bytes.
// `_mm_loadu_si128` allows unaligned loads.
let chunk1 = unsafe { _mm_loadu_si128(ptr as *const __m128i) };
// SAFETY: Same as above - ptr.add(16) is within the valid 32-byte range.
let chunk2 = unsafe { _mm_loadu_si128(ptr.add(16) as *const __m128i) };
// OR them together - if any byte has the high bit set, the result will too.
// SAFETY: SSE2 is guaranteed by the cfg predicate.
let combined = unsafe { _mm_or_si128(chunk1, chunk2) };
// Create a mask from the MSBs of each byte.
// If any byte is >= 128, its MSB is 1, so the mask will be non-zero.
// SAFETY: SSE2 is guaranteed by the cfg predicate.
let mask = unsafe { _mm_movemask_epi8(combined) };
if mask != 0 {
return false;
}
i += CHUNK_SIZE;
}
// Handle remaining bytes with simple loop
while i < bytes.len() {
if !bytes[i].is_ascii() {
return false;
}
i += 1;
}
true
}
/// ASCII test optimized to use the `pmovmskb` instruction on `x86-64`.
///
/// Uses explicit SSE2 intrinsics to prevent LLVM from auto-vectorizing with
/// broken AVX-512 code that extracts mask bits one-by-one.
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn is_ascii(bytes: &[u8]) -> bool {
const USIZE_SIZE: usize = size_of::<usize>();
const NONASCII_MASK: usize = usize::MAX / 255 * 0x80;
const_eval_select!(
@capture { bytes: &[u8] } -> bool:
if const {
is_ascii_simple(bytes)
} else {
// For small inputs, use usize-at-a-time processing to avoid SSE2 call overhead.
if bytes.len() < CHUNK_SIZE {
let chunks = bytes.chunks_exact(USIZE_SIZE);
let remainder = chunks.remainder();
for chunk in chunks {
let word = usize::from_ne_bytes(chunk.try_into().unwrap());
if (word & NONASCII_MASK) != 0 {
return false;
}
}
return remainder.iter().all(|b| b.is_ascii());
}
is_ascii_sse2(bytes)
}
)
}
/// ASCII test optimized to use the `vmskltz.b` instruction on `loongarch64`.
///
/// Other platforms are not likely to benefit from this code structure, so they
/// use SWAR techniques to test for ASCII in `usize`-sized chunks.
#[cfg(any(
all(target_arch = "x86_64", target_feature = "sse2"),
all(target_arch = "loongarch64", target_feature = "lsx")
))]
#[cfg(all(target_arch = "loongarch64", target_feature = "lsx"))]
#[inline]
const fn is_ascii(bytes: &[u8]) -> bool {
// Process chunks of 32 bytes at a time in the fast path to enable
// auto-vectorization and use of `pmovmskb`. Two 128-bit vector registers
// auto-vectorization and use of `vmskltz.b`. Two 128-bit vector registers
// can be OR'd together and then the resulting vector can be tested for
// non-ASCII bytes.
const CHUNK_SIZE: usize = 32;
@ -485,7 +564,7 @@ const fn is_ascii(bytes: &[u8]) -> bool {
while i + CHUNK_SIZE <= bytes.len() {
let chunk_end = i + CHUNK_SIZE;
// Get LLVM to produce a `pmovmskb` instruction on x86-64 which
// Get LLVM to produce a `vmskltz.b` instruction on loongarch64 which
// creates a mask from the most significant bit of each byte.
// ASCII bytes are less than 128 (0x80), so their most significant
// bit is unset.

View file

@ -82,6 +82,10 @@ pub fn test_bool_not() {
}
}
const fn zero() -> i32 {
0
}
#[test]
fn test_bool_to_option() {
assert_eq!(false.then_some(0), None);
@ -89,11 +93,6 @@ fn test_bool_to_option() {
assert_eq!(false.then(|| 0), None);
assert_eq!(true.then(|| 0), Some(0));
/* FIXME(#110395)
const fn zero() -> i32 {
0
}
const A: Option<i32> = false.then_some(0);
const B: Option<i32> = true.then_some(0);
const C: Option<i32> = false.then(zero);
@ -103,7 +102,6 @@ fn test_bool_to_option() {
assert_eq!(B, Some(0));
assert_eq!(C, None);
assert_eq!(D, Some(0));
*/
}
#[test]
@ -112,4 +110,14 @@ fn test_bool_to_result() {
assert_eq!(true.ok_or(0), Ok(()));
assert_eq!(false.ok_or_else(|| 0), Err(0));
assert_eq!(true.ok_or_else(|| 0), Ok(()));
const A: Result<(), i32> = false.ok_or(0);
const B: Result<(), i32> = true.ok_or(0);
const C: Result<(), i32> = false.ok_or_else(zero);
const D: Result<(), i32> = true.ok_or_else(zero);
assert_eq!(A, Err(0));
assert_eq!(B, Ok(()));
assert_eq!(C, Err(0));
assert_eq!(D, Ok(()));
}

View file

@ -391,7 +391,7 @@ float_test! {
}
}
// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on
// FIXME(f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on
// all platforms.
float_test! {
name: num_rem,
@ -1357,15 +1357,11 @@ float_test! {
}
}
// FIXME(f16): Tests involving sNaN are disabled because without optimizations, `total_cmp` is
// getting incorrectly lowered to code that includes a `extend`/`trunc` round trip, which quiets
// sNaNs. See: https://github.com/llvm/llvm-project/issues/104915
float_test! {
name: total_cmp_s_nan,
attrs: {
const: #[cfg(false)],
f16: #[cfg(miri)],
f16: #[cfg(any(miri, target_has_reliable_f16_math))],
f128: #[cfg(any(miri, target_has_reliable_f128_math))],
},
test<Float> {
@ -1636,7 +1632,7 @@ float_test! {
}
}
// FIXME(f16_f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added.
// FIXME(f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added.
// float_test! {
// name: from_u64_i64,
// attrs: {

View file

@ -17,6 +17,7 @@
#![feature(clamp_magnitude)]
#![feature(clone_to_uninit)]
#![feature(const_array)]
#![feature(const_bool)]
#![feature(const_cell_traits)]
#![feature(const_clone)]
#![feature(const_cmp)]

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