Merge from rustc

This commit is contained in:
Ralf Jung 2025-05-29 11:51:37 +02:00
commit 1b6a290656
241 changed files with 3309 additions and 2191 deletions

View file

@ -3417,9 +3417,9 @@ impl Item {
ItemKind::Fn(i) => Some(&i.generics),
ItemKind::TyAlias(i) => Some(&i.generics),
ItemKind::TraitAlias(_, generics, _)
| ItemKind::Enum(_, _, generics)
| ItemKind::Struct(_, _, generics)
| ItemKind::Union(_, _, generics) => Some(&generics),
| ItemKind::Enum(_, generics, _)
| ItemKind::Struct(_, generics, _)
| ItemKind::Union(_, generics, _) => Some(&generics),
ItemKind::Trait(i) => Some(&i.generics),
ItemKind::Impl(i) => Some(&i.generics),
}
@ -3663,15 +3663,15 @@ pub enum ItemKind {
/// An enum definition (`enum`).
///
/// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
Enum(Ident, EnumDef, Generics),
Enum(Ident, Generics, EnumDef),
/// A struct definition (`struct`).
///
/// E.g., `struct Foo<A> { x: A }`.
Struct(Ident, VariantData, Generics),
Struct(Ident, Generics, VariantData),
/// A union definition (`union`).
///
/// E.g., `union Foo<A, B> { x: A, y: B }`.
Union(Ident, VariantData, Generics),
Union(Ident, Generics, VariantData),
/// A trait declaration (`trait`).
///
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
@ -3688,10 +3688,8 @@ pub enum ItemKind {
///
/// E.g., `foo!(..)`.
MacCall(P<MacCall>),
/// A macro definition.
MacroDef(Ident, MacroDef),
/// A single delegation item (`reuse`).
///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
@ -3767,9 +3765,9 @@ impl ItemKind {
Self::Fn(box Fn { generics, .. })
| Self::TyAlias(box TyAlias { generics, .. })
| Self::Const(box ConstItem { generics, .. })
| Self::Enum(_, _, generics)
| Self::Struct(_, _, generics)
| Self::Union(_, _, generics)
| Self::Enum(_, generics, _)
| Self::Struct(_, generics, _)
| Self::Union(_, generics, _)
| Self::Trait(box Trait { generics, .. })
| Self::TraitAlias(_, generics, _)
| Self::Impl(box Impl { generics, .. }) => Some(generics),

View file

@ -508,7 +508,7 @@ macro_rules! common_visitor_and_walkers {
)?
$(<V as Visitor<$lt>>::Result::output())?
}
ItemKind::Enum(ident, enum_definition, generics) => {
ItemKind::Enum(ident, generics, enum_definition) => {
try_visit!(vis.visit_ident(ident));
try_visit!(vis.visit_generics(generics));
$(${ignore($mut)}
@ -516,8 +516,8 @@ macro_rules! common_visitor_and_walkers {
)?
$(${ignore($lt)}vis.visit_enum_def(enum_definition))?
}
ItemKind::Struct(ident, variant_data, generics)
| ItemKind::Union(ident, variant_data, generics) => {
ItemKind::Struct(ident, generics, variant_data)
| ItemKind::Union(ident, generics, variant_data) => {
try_visit!(vis.visit_ident(ident));
try_visit!(vis.visit_generics(generics));
vis.visit_variant_data(variant_data)

View file

@ -306,7 +306,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ItemKind::TyAlias(ident, ty, generics)
}
ItemKind::Enum(ident, enum_definition, generics) => {
ItemKind::Enum(ident, generics, enum_definition) => {
let ident = self.lower_ident(*ident);
let (generics, variants) = self.lower_generics(
generics,
@ -320,7 +320,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ItemKind::Enum(ident, hir::EnumDef { variants }, generics)
}
ItemKind::Struct(ident, struct_def, generics) => {
ItemKind::Struct(ident, generics, struct_def) => {
let ident = self.lower_ident(*ident);
let (generics, struct_def) = self.lower_generics(
generics,
@ -330,7 +330,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ItemKind::Struct(ident, struct_def, generics)
}
ItemKind::Union(ident, vdata, generics) => {
ItemKind::Union(ident, generics, vdata) => {
let ident = self.lower_ident(*ident);
let (generics, vdata) = self.lower_generics(
generics,

View file

@ -1010,7 +1010,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
self.extern_mod_span = old_item;
}
ItemKind::Enum(_, def, _) => {
ItemKind::Enum(_, _, def) => {
for variant in &def.variants {
self.visibility_not_permitted(
&variant.vis,
@ -1061,7 +1061,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
visit::walk_item(self, item)
}
ItemKind::Struct(ident, vdata, generics) => match vdata {
ItemKind::Struct(ident, generics, vdata) => match vdata {
VariantData::Struct { fields, .. } => {
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
self.visit_generics(generics);
@ -1070,7 +1070,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
_ => visit::walk_item(self, item),
},
ItemKind::Union(ident, vdata, generics) => {
ItemKind::Union(ident, generics, vdata) => {
if vdata.fields().is_empty() {
self.dcx().emit_err(errors::FieldlessUnion { span: item.span });
}

View file

@ -298,14 +298,14 @@ impl<'a> State<'a> {
*defaultness,
);
}
ast::ItemKind::Enum(ident, enum_definition, params) => {
self.print_enum_def(enum_definition, params, *ident, item.span, &item.vis);
ast::ItemKind::Enum(ident, generics, enum_definition) => {
self.print_enum_def(enum_definition, generics, *ident, item.span, &item.vis);
}
ast::ItemKind::Struct(ident, struct_def, generics) => {
ast::ItemKind::Struct(ident, generics, struct_def) => {
let (cb, ib) = self.head(visibility_qualified(&item.vis, "struct"));
self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
}
ast::ItemKind::Union(ident, struct_def, generics) => {
ast::ItemKind::Union(ident, generics, struct_def) => {
let (cb, ib) = self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
}

View file

@ -56,7 +56,6 @@ builtin_macros_assert_requires_expression = macro requires an expression as an a
builtin_macros_autodiff = autodiff must be applied to function
builtin_macros_autodiff_missing_config = autodiff requires at least a name and mode
builtin_macros_autodiff_mode = unknown Mode: `{$mode}`. Use `Forward` or `Reverse`
builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode
builtin_macros_autodiff_not_build = this rustc version does not support autodiff
builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found}

View file

@ -86,27 +86,23 @@ mod llvm_enzyme {
ecx: &mut ExtCtxt<'_>,
meta_item: &ThinVec<MetaItemInner>,
has_ret: bool,
mode: DiffMode,
) -> AutoDiffAttrs {
let dcx = ecx.sess.dcx();
let mode = name(&meta_item[1]);
let Ok(mode) = DiffMode::from_str(&mode) else {
dcx.emit_err(errors::AutoDiffInvalidMode { span: meta_item[1].span(), mode });
return AutoDiffAttrs::error();
};
// Now we check, whether the user wants autodiff in batch/vector mode, or scalar mode.
// If he doesn't specify an integer (=width), we default to scalar mode, thus width=1.
let mut first_activity = 2;
let mut first_activity = 1;
let width = if let [_, _, x, ..] = &meta_item[..]
let width = if let [_, x, ..] = &meta_item[..]
&& let Some(x) = width(x)
{
first_activity = 3;
first_activity = 2;
match x.try_into() {
Ok(x) => x,
Err(_) => {
dcx.emit_err(errors::AutoDiffInvalidWidth {
span: meta_item[2].span(),
span: meta_item[1].span(),
width: x,
});
return AutoDiffAttrs::error();
@ -165,6 +161,24 @@ mod llvm_enzyme {
ts.push(TokenTree::Token(comma.clone(), Spacing::Alone));
}
pub(crate) fn expand_forward(
ecx: &mut ExtCtxt<'_>,
expand_span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
expand_with_mode(ecx, expand_span, meta_item, item, DiffMode::Forward)
}
pub(crate) fn expand_reverse(
ecx: &mut ExtCtxt<'_>,
expand_span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
expand_with_mode(ecx, expand_span, meta_item, item, DiffMode::Reverse)
}
/// We expand the autodiff macro to generate a new placeholder function which passes
/// type-checking and can be called by users. The function body of the placeholder function will
/// later be replaced on LLVM-IR level, so the design of the body is less important and for now
@ -198,11 +212,12 @@ mod llvm_enzyme {
/// ```
/// FIXME(ZuseZ4): Once autodiff is enabled by default, make this a doc comment which is checked
/// in CI.
pub(crate) fn expand(
pub(crate) fn expand_with_mode(
ecx: &mut ExtCtxt<'_>,
expand_span: Span,
meta_item: &ast::MetaItem,
mut item: Annotatable,
mode: DiffMode,
) -> Vec<Annotatable> {
if cfg!(not(llvm_enzyme)) {
ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span });
@ -245,29 +260,41 @@ mod llvm_enzyme {
// create TokenStream from vec elemtents:
// meta_item doesn't have a .tokens field
let mut ts: Vec<TokenTree> = vec![];
if meta_item_vec.len() < 2 {
// At the bare minimum, we need a fnc name and a mode, even for a dummy function with no
// input and output args.
if meta_item_vec.len() < 1 {
// At the bare minimum, we need a fnc name.
dcx.emit_err(errors::AutoDiffMissingConfig { span: item.span() });
return vec![item];
}
meta_item_inner_to_ts(&meta_item_vec[1], &mut ts);
let mode_symbol = match mode {
DiffMode::Forward => sym::Forward,
DiffMode::Reverse => sym::Reverse,
_ => unreachable!("Unsupported mode: {:?}", mode),
};
// Insert mode token
let mode_token = Token::new(TokenKind::Ident(mode_symbol, false.into()), Span::default());
ts.insert(0, TokenTree::Token(mode_token, Spacing::Joint));
ts.insert(
1,
TokenTree::Token(Token::new(TokenKind::Comma, Span::default()), Spacing::Alone),
);
// Now, if the user gave a width (vector aka batch-mode ad), then we copy it.
// If it is not given, we default to 1 (scalar mode).
let start_position;
let kind: LitKind = LitKind::Integer;
let symbol;
if meta_item_vec.len() >= 3
&& let Some(width) = width(&meta_item_vec[2])
if meta_item_vec.len() >= 2
&& let Some(width) = width(&meta_item_vec[1])
{
start_position = 3;
start_position = 2;
symbol = Symbol::intern(&width.to_string());
} else {
start_position = 2;
start_position = 1;
symbol = sym::integer(1);
}
let l: Lit = Lit { kind, symbol, suffix: None };
let t = Token::new(TokenKind::Literal(l), Span::default());
let comma = Token::new(TokenKind::Comma, Span::default());
@ -289,7 +316,7 @@ mod llvm_enzyme {
ts.pop();
let ts: TokenStream = TokenStream::from_iter(ts);
let x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret);
let x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret, mode);
if !x.is_active() {
// We encountered an error, so we return the original item.
// This allows us to potentially parse other attributes.
@ -1017,4 +1044,4 @@ mod llvm_enzyme {
}
}
pub(crate) use llvm_enzyme::expand;
pub(crate) use llvm_enzyme::{expand_forward, expand_reverse};

View file

@ -34,8 +34,8 @@ pub(crate) fn expand_deriving_clone(
let is_simple;
match item {
Annotatable::Item(annitem) => match &annitem.kind {
ItemKind::Struct(_, _, Generics { params, .. })
| ItemKind::Enum(_, _, Generics { params, .. }) => {
ItemKind::Struct(_, Generics { params, .. }, _)
| ItemKind::Enum(_, Generics { params, .. }, _) => {
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
if has_derive_copy

View file

@ -21,7 +21,7 @@ pub(crate) fn expand_deriving_partial_ord(
// Order in which to perform matching
let discr_then_data = if let Annotatable::Item(item) = item
&& let ItemKind::Enum(_, def, _) = &item.kind
&& let ItemKind::Enum(_, _, def) = &item.kind
{
let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
match dataful.iter().filter(|&&b| b).count() {

View file

@ -30,7 +30,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
item.visit_with(&mut DetectNonGenericPointeeAttr { cx });
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
&& let ItemKind::Struct(ident, struct_data, g) = &aitem.kind
&& let ItemKind::Struct(ident, g, struct_data) = &aitem.kind
{
if !matches!(
struct_data,

View file

@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> {
);
let newitem = match &item.kind {
ast::ItemKind::Struct(ident, struct_def, generics) => self.expand_struct_def(
ast::ItemKind::Struct(ident, generics, struct_def) => self.expand_struct_def(
cx,
struct_def,
*ident,
@ -496,7 +496,7 @@ impl<'a> TraitDef<'a> {
from_scratch,
is_packed,
),
ast::ItemKind::Enum(ident, enum_def, generics) => {
ast::ItemKind::Enum(ident, generics, enum_def) => {
// We ignore `is_packed` here, because `repr(packed)`
// enums cause an error later on.
//
@ -504,7 +504,7 @@ impl<'a> TraitDef<'a> {
// downstream in blatantly illegal code, so it is fine.
self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch)
}
ast::ItemKind::Union(ident, struct_def, generics) => {
ast::ItemKind::Union(ident, generics, struct_def) => {
if self.supports_unions {
self.expand_struct_def(
cx,

View file

@ -180,14 +180,6 @@ mod autodiff {
pub(crate) act: String,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_autodiff_mode)]
pub(crate) struct AutoDiffInvalidMode {
#[primary_span]
pub(crate) span: Span,
pub(crate) mode: String,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_autodiff_width)]
pub(crate) struct AutoDiffInvalidWidth {

View file

@ -5,10 +5,10 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(not(bootstrap), feature(autodiff))]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(autodiff)]
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
@ -112,7 +112,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
register_attr! {
alloc_error_handler: alloc_error_handler::expand,
autodiff: autodiff::expand,
autodiff_forward: autodiff::expand_forward,
autodiff_reverse: autodiff::expand_reverse,
bench: test::expand_bench,
cfg_accessible: cfg_accessible::Expander,
cfg_eval: cfg_eval::expand,

View file

@ -22,11 +22,11 @@ use rustc_codegen_ssa::traits::{
};
use rustc_middle::bug;
#[cfg(feature = "master")]
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
use rustc_middle::ty::{self, Instance, Ty};
use rustc_span::{Span, Symbol, sym};
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use rustc_target::callconv::{ArgAbi, PassMode};
use rustc_target::spec::PanicStrategy;
#[cfg(feature = "master")]
@ -200,9 +200,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
fn codegen_intrinsic_call(
&mut self,
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, RValue<'gcc>>],
llresult: RValue<'gcc>,
result: PlaceRef<'tcx, RValue<'gcc>>,
span: Span,
) -> Result<(), Instance<'tcx>> {
let tcx = self.tcx;
@ -221,7 +220,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let name_str = name.as_str();
let llret_ty = self.layout_of(ret_ty).gcc_type(self);
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
let simple = get_simple_intrinsic(self, name);
let simple_func = get_simple_function(self, name);
@ -271,7 +269,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
args[0].immediate(),
args[1].immediate(),
args[2].immediate(),
llresult,
result,
);
return Ok(());
}
@ -286,17 +284,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
}
sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = fn_args.type_at(0);
let ptr = args[0].immediate();
let layout = self.layout_of(tp_ty);
let load = if let PassMode::Cast { cast: ref ty, pad_i32: _ } = fn_abi.ret.mode {
let gcc_ty = ty.gcc_type(self);
self.volatile_load(gcc_ty, ptr)
} else {
self.volatile_load(layout.gcc_type(self), ptr)
};
let load = self.volatile_load(result.layout.gcc_type(self), ptr);
// TODO(antoyo): set alignment.
if let BackendRepr::Scalar(scalar) = layout.backend_repr {
if let BackendRepr::Scalar(scalar) = result.layout.backend_repr {
self.to_immediate_scalar(load, scalar)
} else {
load
@ -511,16 +502,14 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
_ => return Err(Instance::new_raw(instance.def_id(), instance.args)),
};
if !fn_abi.ret.is_ignore() {
if let PassMode::Cast { cast: ref ty, .. } = fn_abi.ret.mode {
let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
let ptr = self.pointercast(result.val.llval, ptr_llty);
self.store(value, ptr, result.val.align);
} else {
OperandRef::from_immediate_or_packed_pair(self, value, result.layout)
.val
.store(self, result);
}
if result.layout.ty.is_bool() {
OperandRef::from_immediate_or_packed_pair(self, value, result.layout)
.val
.store(self, result);
} else if !result.layout.ty.is_unit() {
let ptr_llty = self.type_ptr_to(result.layout.gcc_type(self));
let ptr = self.pointercast(result.val.llval, ptr_llty);
self.store(value, ptr, result.val.align);
}
Ok(())
}
@ -1230,14 +1219,13 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(
try_func: RValue<'gcc>,
data: RValue<'gcc>,
_catch_func: RValue<'gcc>,
dest: RValue<'gcc>,
dest: PlaceRef<'tcx, RValue<'gcc>>,
) {
if bx.sess().panic_strategy() == PanicStrategy::Abort {
bx.call(bx.type_void(), None, None, try_func, &[data], None, None);
// Return 0 unconditionally from the intrinsic call;
// we can never unwind.
let ret_align = bx.tcx.data_layout.i32_align.abi;
bx.store(bx.const_i32(0), dest, ret_align);
OperandValue::Immediate(bx.const_i32(0)).store(bx, dest);
} else {
if wants_msvc_seh(bx.sess()) {
unimplemented!();
@ -1261,12 +1249,12 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(
// functions in play. By calling a shim we're guaranteed that our shim will have
// the right personality function.
#[cfg(feature = "master")]
fn codegen_gnu_try<'gcc>(
bx: &mut Builder<'_, 'gcc, '_>,
fn codegen_gnu_try<'gcc, 'tcx>(
bx: &mut Builder<'_, 'gcc, 'tcx>,
try_func: RValue<'gcc>,
data: RValue<'gcc>,
catch_func: RValue<'gcc>,
dest: RValue<'gcc>,
dest: PlaceRef<'tcx, RValue<'gcc>>,
) {
let cx: &CodegenCx<'gcc, '_> = bx.cx;
let (llty, func) = get_rust_try_fn(cx, &mut |mut bx| {
@ -1322,8 +1310,7 @@ fn codegen_gnu_try<'gcc>(
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None, None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
OperandValue::Immediate(ret).store(bx, dest);
}
// Helper function used to get a handle to the `__rust_try` function used to

View file

@ -15,11 +15,10 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty};
use rustc_middle::{bug, span_bug};
use rustc_span::{Span, Symbol, sym};
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::callconv::{FnAbi, PassMode};
use rustc_target::spec::{HasTargetSpec, PanicStrategy};
use tracing::debug;
use crate::abi::{FnAbiLlvmExt, LlvmType};
use crate::abi::FnAbiLlvmExt;
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm::{self, Metadata};
@ -165,9 +164,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
fn codegen_intrinsic_call(
&mut self,
instance: ty::Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, &'ll Value>],
llresult: &'ll Value,
result: PlaceRef<'tcx, &'ll Value>,
span: Span,
) -> Result<(), ty::Instance<'tcx>> {
let tcx = self.tcx;
@ -184,7 +182,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
let name = tcx.item_name(def_id);
let llret_ty = self.layout_of(ret_ty).llvm_type(self);
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
let simple = get_simple_intrinsic(self, name);
let llval = match name {
@ -255,7 +252,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
args[0].immediate(),
args[1].immediate(),
args[2].immediate(),
llresult,
result,
);
return Ok(());
}
@ -264,7 +261,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()])
}
sym::va_arg => {
match fn_abi.ret.layout.backend_repr {
match result.layout.backend_repr {
BackendRepr::Scalar(scalar) => {
match scalar.primitive() {
Primitive::Int(..) => {
@ -299,18 +296,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = fn_args.type_at(0);
let ptr = args[0].immediate();
let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode {
let llty = ty.llvm_type(self);
self.volatile_load(llty, ptr)
} else {
self.volatile_load(self.layout_of(tp_ty).llvm_type(self), ptr)
};
let load = self.volatile_load(result.layout.llvm_type(self), ptr);
let align = if name == sym::unaligned_volatile_load {
1
} else {
self.align_of(tp_ty).bytes() as u32
result.layout.align.abi.bytes() as u32
};
unsafe {
llvm::LLVMSetAlignment(load, align);
@ -629,14 +620,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
};
if !fn_abi.ret.is_ignore() {
if let PassMode::Cast { .. } = &fn_abi.ret.mode {
self.store(llval, result.val.llval, result.val.align);
} else {
OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
.val
.store(self, result);
}
if result.layout.ty.is_bool() {
OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
.val
.store(self, result);
} else if !result.layout.ty.is_unit() {
self.store_to_place(llval, result.val);
}
Ok(())
}
@ -688,20 +677,19 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
}
fn catch_unwind_intrinsic<'ll>(
bx: &mut Builder<'_, 'll, '_>,
fn catch_unwind_intrinsic<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
dest: &'ll Value,
dest: PlaceRef<'tcx, &'ll Value>,
) {
if bx.sess().panic_strategy() == PanicStrategy::Abort {
let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
bx.call(try_func_ty, None, None, try_func, &[data], None, None);
// Return 0 unconditionally from the intrinsic call;
// we can never unwind.
let ret_align = bx.tcx().data_layout.i32_align.abi;
bx.store(bx.const_i32(0), dest, ret_align);
OperandValue::Immediate(bx.const_i32(0)).store(bx, dest);
} else if wants_msvc_seh(bx.sess()) {
codegen_msvc_try(bx, try_func, data, catch_func, dest);
} else if wants_wasm_eh(bx.sess()) {
@ -720,12 +708,12 @@ fn catch_unwind_intrinsic<'ll>(
// instructions are meant to work for all targets, as of the time of this
// writing, however, LLVM does not recommend the usage of these new instructions
// as the old ones are still more optimized.
fn codegen_msvc_try<'ll>(
bx: &mut Builder<'_, 'll, '_>,
fn codegen_msvc_try<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
dest: &'ll Value,
dest: PlaceRef<'tcx, &'ll Value>,
) {
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
bx.set_personality_fn(bx.eh_personality());
@ -865,17 +853,16 @@ fn codegen_msvc_try<'ll>(
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
OperandValue::Immediate(ret).store(bx, dest);
}
// WASM's definition of the `rust_try` function.
fn codegen_wasm_try<'ll>(
bx: &mut Builder<'_, 'll, '_>,
fn codegen_wasm_try<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
dest: &'ll Value,
dest: PlaceRef<'tcx, &'ll Value>,
) {
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
bx.set_personality_fn(bx.eh_personality());
@ -939,8 +926,7 @@ fn codegen_wasm_try<'ll>(
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
OperandValue::Immediate(ret).store(bx, dest);
}
// Definition of the standard `try` function for Rust using the GNU-like model
@ -954,12 +940,12 @@ fn codegen_wasm_try<'ll>(
// function calling it, and that function may already have other personality
// functions in play. By calling a shim we're guaranteed that our shim will have
// the right personality function.
fn codegen_gnu_try<'ll>(
bx: &mut Builder<'_, 'll, '_>,
fn codegen_gnu_try<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
dest: &'ll Value,
dest: PlaceRef<'tcx, &'ll Value>,
) {
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
// Codegens the shims described above:
@ -1006,19 +992,18 @@ fn codegen_gnu_try<'ll>(
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
OperandValue::Immediate(ret).store(bx, dest);
}
// Variant of codegen_gnu_try used for emscripten where Rust panics are
// implemented using C++ exceptions. Here we use exceptions of a specific type
// (`struct rust_panic`) to represent Rust panics.
fn codegen_emcc_try<'ll>(
bx: &mut Builder<'_, 'll, '_>,
fn codegen_emcc_try<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
dest: &'ll Value,
dest: PlaceRef<'tcx, &'ll Value>,
) {
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
// Codegens the shims described above:
@ -1089,8 +1074,7 @@ fn codegen_emcc_try<'ll>(
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
OperandValue::Immediate(ret).store(bx, dest);
}
// Helper function to give a Block to a closure to codegen a shim function.

View file

@ -68,6 +68,23 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
}
}
fn check_link_info_print_request(sess: &Session, crate_types: &[CrateType]) {
let print_native_static_libs =
sess.opts.prints.iter().any(|p| p.kind == PrintKind::NativeStaticLibs);
let has_staticlib = crate_types.iter().any(|ct| *ct == CrateType::Staticlib);
if print_native_static_libs {
if !has_staticlib {
sess.dcx()
.warn(format!("cannot output linkage information without staticlib crate-type"));
sess.dcx()
.note(format!("consider `--crate-type staticlib` to print linkage information"));
} else if !sess.opts.output_types.should_link() {
sess.dcx()
.warn(format!("cannot output linkage information when --emit link is not passed"));
}
}
}
/// Performs the linkage portion of the compilation phase. This will generate all
/// of the requested outputs for this compilation session.
pub fn link_binary(
@ -180,6 +197,8 @@ pub fn link_binary(
}
}
check_link_info_print_request(sess, &codegen_results.crate_info.crate_types);
// Remove the temporary object file and metadata if we aren't saving temps.
sess.time("link_binary_remove_temps", || {
// If the user requests that temporaries are saved, don't delete any.

View file

@ -11,8 +11,8 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
use rustc_session::config::OptLevel;
use rustc_span::Span;
use rustc_span::source_map::Spanned;
use rustc_span::{Span, sym};
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use tracing::{debug, info};
@ -827,7 +827,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
helper: &TerminatorCodegenHelper<'tcx>,
bx: &mut Bx,
intrinsic: ty::IntrinsicDef,
instance: Option<Instance<'tcx>>,
instance: Instance<'tcx>,
source_info: mir::SourceInfo,
target: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
@ -836,58 +836,56 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Emit a panic or a no-op for `assert_*` intrinsics.
// These are intrinsics that compile to panics so that we can get a message
// which mentions the offending type, even from a const context.
if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) {
let ty = instance.unwrap().args.type_at(0);
let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) else {
return None;
};
let do_panic = !bx
.tcx()
.check_validity_requirement((requirement, bx.typing_env().as_query_input(ty)))
.expect("expect to have layout during codegen");
let ty = instance.args.type_at(0);
let layout = bx.layout_of(ty);
let is_valid = bx
.tcx()
.check_validity_requirement((requirement, bx.typing_env().as_query_input(ty)))
.expect("expect to have layout during codegen");
Some(if do_panic {
let msg_str = with_no_visible_paths!({
with_no_trimmed_paths!({
if layout.is_uninhabited() {
// Use this error even for the other intrinsics as it is more precise.
format!("attempted to instantiate uninhabited type `{ty}`")
} else if requirement == ValidityRequirement::Zero {
format!("attempted to zero-initialize type `{ty}`, which is invalid")
} else {
format!(
"attempted to leave type `{ty}` uninitialized, which is invalid"
)
}
})
});
let msg = bx.const_str(&msg_str);
// Obtain the panic entry point.
let (fn_abi, llfn, instance) =
common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
// Codegen the actual panic invoke/call.
helper.do_call(
self,
bx,
fn_abi,
llfn,
&[msg.0, msg.1],
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
unwind,
&[],
Some(instance),
mergeable_succ,
)
} else {
// a NOP
let target = target.unwrap();
helper.funclet_br(self, bx, target, mergeable_succ)
})
} else {
None
if is_valid {
// a NOP
let target = target.unwrap();
return Some(helper.funclet_br(self, bx, target, mergeable_succ));
}
let layout = bx.layout_of(ty);
let msg_str = with_no_visible_paths!({
with_no_trimmed_paths!({
if layout.is_uninhabited() {
// Use this error even for the other intrinsics as it is more precise.
format!("attempted to instantiate uninhabited type `{ty}`")
} else if requirement == ValidityRequirement::Zero {
format!("attempted to zero-initialize type `{ty}`, which is invalid")
} else {
format!("attempted to leave type `{ty}` uninitialized, which is invalid")
}
})
});
let msg = bx.const_str(&msg_str);
// Obtain the panic entry point.
let (fn_abi, llfn, instance) =
common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
// Codegen the actual panic invoke/call.
Some(helper.do_call(
self,
bx,
fn_abi,
llfn,
&[msg.0, msg.1],
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
unwind,
&[],
Some(instance),
mergeable_succ,
))
}
fn codegen_call_terminator(
@ -903,42 +901,127 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn_span: Span,
mergeable_succ: bool,
) -> MergingSucc {
let source_info = terminator.source_info;
let span = source_info.span;
let source_info = mir::SourceInfo { span: fn_span, ..terminator.source_info };
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
let callee = self.codegen_operand(bx, func);
let (instance, mut llfn) = match *callee.layout.ty.kind() {
ty::FnDef(def_id, args) => (
Some(ty::Instance::expect_resolve(
ty::FnDef(def_id, generic_args) => {
let instance = ty::Instance::expect_resolve(
bx.tcx(),
bx.typing_env(),
def_id,
args,
generic_args,
fn_span,
)),
None,
),
);
let instance = match instance.def {
// We don't need AsyncDropGlueCtorShim here because it is not `noop func`,
// it is `func returning noop future`
ty::InstanceKind::DropGlue(_, None) => {
// Empty drop glue; a no-op.
let target = target.unwrap();
return helper.funclet_br(self, bx, target, mergeable_succ);
}
ty::InstanceKind::Intrinsic(def_id) => {
let intrinsic = bx.tcx().intrinsic(def_id).unwrap();
if let Some(merging_succ) = self.codegen_panic_intrinsic(
&helper,
bx,
intrinsic,
instance,
source_info,
target,
unwind,
mergeable_succ,
) {
return merging_succ;
}
let result_layout =
self.cx.layout_of(self.monomorphized_place_ty(destination.as_ref()));
let (result, store_in_local) = if result_layout.is_zst() {
(
PlaceRef::new_sized(bx.const_undef(bx.type_ptr()), result_layout),
None,
)
} else if let Some(local) = destination.as_local() {
match self.locals[local] {
LocalRef::Place(dest) => (dest, None),
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
LocalRef::PendingOperand => {
// Currently, intrinsics always need a location to store
// the result, so we create a temporary `alloca` for the
// result.
let tmp = PlaceRef::alloca(bx, result_layout);
tmp.storage_live(bx);
(tmp, Some(local))
}
LocalRef::Operand(_) => {
bug!("place local already assigned to");
}
}
} else {
(self.codegen_place(bx, destination.as_ref()), None)
};
if result.val.align < result.layout.align.abi {
// Currently, MIR code generation does not create calls
// that store directly to fields of packed structs (in
// fact, the calls it creates write only to temps).
//
// If someone changes that, please update this code path
// to create a temporary.
span_bug!(self.mir.span, "can't directly store to unaligned value");
}
let args: Vec<_> =
args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect();
match self.codegen_intrinsic_call(bx, instance, &args, result, source_info)
{
Ok(()) => {
if let Some(local) = store_in_local {
let op = bx.load_operand(result);
result.storage_dead(bx);
self.overwrite_local(local, LocalRef::Operand(op));
self.debug_introduce_local(bx, local);
}
return if let Some(target) = target {
helper.funclet_br(self, bx, target, mergeable_succ)
} else {
bx.unreachable();
MergingSucc::False
};
}
Err(instance) => {
if intrinsic.must_be_overridden {
span_bug!(
fn_span,
"intrinsic {} must be overridden by codegen backend, but isn't",
intrinsic.name,
);
}
instance
}
}
}
_ => instance,
};
(Some(instance), None)
}
ty::FnPtr(..) => (None, Some(callee.immediate())),
_ => bug!("{} is not callable", callee.layout.ty),
};
let def = instance.map(|i| i.def);
// We don't need AsyncDropGlueCtorShim here because it is not `noop func`,
// it is `func returning noop future`
if let Some(ty::InstanceKind::DropGlue(_, None)) = def {
// Empty drop glue; a no-op.
let target = target.unwrap();
return helper.funclet_br(self, bx, target, mergeable_succ);
}
// FIXME(eddyb) avoid computing this if possible, when `instance` is
// available - right now `sig` is only needed for getting the `abi`
// and figuring out how many extra args were passed to a C-variadic `fn`.
let sig = callee.layout.ty.fn_sig(bx.tcx());
let abi = sig.abi();
let extra_args = &args[sig.inputs().skip_binder().len()..];
let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| {
@ -954,93 +1037,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// The arguments we'll be passing. Plus one to account for outptr, if used.
let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
let instance = match def {
Some(ty::InstanceKind::Intrinsic(def_id)) => {
let intrinsic = bx.tcx().intrinsic(def_id).unwrap();
if let Some(merging_succ) = self.codegen_panic_intrinsic(
&helper,
bx,
intrinsic,
instance,
source_info,
target,
unwind,
mergeable_succ,
) {
return merging_succ;
}
let mut llargs = Vec::with_capacity(1);
let ret_dest = self.make_return_dest(
bx,
destination,
&fn_abi.ret,
&mut llargs,
Some(intrinsic),
);
let dest = match ret_dest {
_ if fn_abi.ret.is_indirect() => llargs[0],
ReturnDest::Nothing => bx.const_undef(bx.type_ptr()),
ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.val.llval,
ReturnDest::DirectOperand(_) => {
bug!("Cannot use direct operand with an intrinsic call")
}
};
let args: Vec<_> =
args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect();
if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) {
let location = self
.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
assert_eq!(llargs, []);
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
location.val.store(bx, tmp);
}
self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate());
return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ);
}
let instance = *instance.as_ref().unwrap();
match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) {
Ok(()) => {
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval);
}
return if let Some(target) = target {
helper.funclet_br(self, bx, target, mergeable_succ)
} else {
bx.unreachable();
MergingSucc::False
};
}
Err(instance) => {
if intrinsic.must_be_overridden {
span_bug!(
span,
"intrinsic {} must be overridden by codegen backend, but isn't",
intrinsic.name,
);
}
Some(instance)
}
}
}
_ => instance,
};
let mut llargs = Vec::with_capacity(arg_count);
// We still need to call `make_return_dest` even if there's no `target`, since
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
// and `make_return_dest` adds the return-place indirect pointer to `llargs`.
let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, None);
let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs);
let destination = target.map(|target| (return_dest, target));
// Split the rust-call tupled arguments off.
let (first_args, untuple) = if abi == ExternAbi::RustCall
let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall
&& let Some((tup, args)) = args.split_last()
{
(args, Some(tup))
@ -1055,7 +1061,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
'make_args: for (i, arg) in first_args.iter().enumerate() {
let mut op = self.codegen_operand(bx, &arg.node);
if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, def) {
if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, instance.map(|i| i.def)) {
match op.val {
Pair(data_ptr, meta) => {
// In the case of Rc<Self>, we need to explicitly pass a
@ -1109,7 +1115,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Make sure that we've actually unwrapped the rcvr down
// to a pointer or ref to `dyn* Trait`.
if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() {
span_bug!(span, "can't codegen a virtual call on {:#?}", op);
span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op);
}
let place = op.deref(bx.cx());
let data_place = place.project_field(bx, 0);
@ -1125,7 +1131,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
continue;
}
_ => {
span_bug!(span, "can't codegen a virtual call on {:#?}", op);
span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op);
}
}
}
@ -1175,8 +1181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir_args + 1,
"#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {instance:?} {fn_span:?} {fn_abi:?}",
);
let location =
self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
let location = self.get_caller_location(bx, source_info);
debug!(
"codegen_call_terminator({:?}): location={:?} (fn_span {:?})",
terminator, location, fn_span
@ -1195,9 +1200,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let fn_ptr = match (instance, llfn) {
(Some(instance), None) => bx.get_fn_addr(instance),
(_, Some(llfn)) => llfn,
_ => span_bug!(span, "no instance or llfn for call"),
_ => span_bug!(fn_span, "no instance or llfn for call"),
};
self.set_debug_loc(bx, mir::SourceInfo { span: fn_span, ..source_info });
self.set_debug_loc(bx, source_info);
helper.do_call(
self,
bx,
@ -1667,7 +1672,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
tuple.layout.fields.count()
}
fn get_caller_location(
pub(super) fn get_caller_location(
&mut self,
bx: &mut Bx,
source_info: mir::SourceInfo,
@ -1868,7 +1873,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
dest: mir::Place<'tcx>,
fn_ret: &ArgAbi<'tcx, Ty<'tcx>>,
llargs: &mut Vec<Bx::Value>,
intrinsic: Option<ty::IntrinsicDef>,
) -> ReturnDest<'tcx, Bx::Value> {
// If the return is ignored, we can just return a do-nothing `ReturnDest`.
if fn_ret.is_ignore() {
@ -1888,13 +1892,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
tmp.storage_live(bx);
llargs.push(tmp.val.llval);
ReturnDest::IndirectOperand(tmp, index)
} else if intrinsic.is_some() {
// Currently, intrinsics always need a location to store
// the result, so we create a temporary `alloca` for the
// result.
let tmp = PlaceRef::alloca(bx, fn_ret.layout);
tmp.storage_live(bx);
ReturnDest::IndirectOperand(tmp, index)
} else {
ReturnDest::DirectOperand(index)
};
@ -1904,7 +1901,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
} else {
self.codegen_place(bx, mir::PlaceRef { local: dest.local, projection: dest.projection })
self.codegen_place(bx, dest.as_ref())
};
if fn_ret.is_indirect() {
if dest.val.align < dest.layout.align.abi {

View file

@ -1,9 +1,9 @@
use rustc_abi::WrappingRange;
use rustc_middle::mir::SourceInfo;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::OptLevel;
use rustc_span::{Span, sym};
use rustc_target::callconv::{FnAbi, PassMode};
use rustc_span::sym;
use super::FunctionCx;
use super::operand::OperandRef;
@ -52,13 +52,14 @@ fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
/// In the `Err` case, returns the instance that should be called instead.
pub fn codegen_intrinsic_call(
&mut self,
bx: &mut Bx,
instance: ty::Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, Bx::Value>],
llresult: Bx::Value,
span: Span,
result: PlaceRef<'tcx, Bx::Value>,
source_info: SourceInfo,
) -> Result<(), ty::Instance<'tcx>> {
let span = source_info.span;
let callee_ty = instance.ty(bx.tcx(), bx.typing_env());
let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else {
@ -97,7 +98,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
let llret_ty = bx.backend_type(bx.layout_of(ret_ty));
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
let llval = match name {
sym::abort => {
@ -105,6 +105,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return Ok(());
}
sym::caller_location => {
let location = self.get_caller_location(bx, source_info);
location.val.store(bx, result);
return Ok(());
}
sym::va_start => bx.va_start(args[0].immediate()),
sym::va_end => bx.va_end(args[0].immediate()),
sym::size_of_val => {
@ -528,18 +534,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => {
// Need to use backend-specific things in the implementation.
return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
return bx.codegen_intrinsic_call(instance, args, result, span);
}
};
if !fn_abi.ret.is_ignore() {
if let PassMode::Cast { .. } = &fn_abi.ret.mode {
bx.store_to_place(llval, result.val);
} else {
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
.val
.store(bx, result);
}
if result.layout.ty.is_bool() {
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
.val
.store(bx, result);
} else if !result.layout.ty.is_unit() {
bx.store_to_place(llval, result.val);
}
Ok(())
}

View file

@ -1,9 +1,9 @@
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty;
use rustc_span::Span;
use rustc_target::callconv::FnAbi;
use super::BackendTypes;
use crate::mir::operand::OperandRef;
use crate::mir::place::PlaceRef;
pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
/// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`,
@ -14,9 +14,8 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
fn codegen_intrinsic_call(
&mut self,
instance: ty::Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OperandRef<'tcx, Self::Value>],
llresult: Self::Value,
result: PlaceRef<'tcx, Self::Value>,
span: Span,
) -> Result<(), ty::Instance<'tcx>>;

View file

@ -3,10 +3,7 @@ An unstable feature was used.
Erroneous code example:
```compile_fail,E0658
#[repr(u128)] // error: use of unstable library feature 'repr128'
enum Foo {
Bar(u64),
}
use std::intrinsics; // error: use of unstable library feature `core_intrinsics`
```
If you're using a stable or a beta version of rustc, you won't be able to use
@ -17,12 +14,9 @@ If you're using a nightly version of rustc, just add the corresponding feature
to be able to use it:
```
#![feature(repr128)]
#![feature(core_intrinsics)]
#[repr(u128)] // ok!
enum Foo {
Bar(u64),
}
use std::intrinsics; // ok!
```
[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html

View file

@ -1424,7 +1424,7 @@ pub fn parse_macro_name_and_helper_attrs(
/// See #73345 and #83125 for more details.
/// FIXME(#73933): Remove this eventually.
fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) {
if let ast::ItemKind::Enum(ident, enum_def, _) = &item.kind
if let ast::ItemKind::Enum(ident, _, enum_def) = &item.kind
&& ident.name == sym::ProceduralMasqueradeDummyType
&& let [variant] = &*enum_def.variants
&& variant.ident.name == sym::Input

View file

@ -1319,10 +1319,10 @@ impl InvocationCollectorNode for P<ast::Item> {
let mut idents = Vec::new();
collect_use_tree_leaves(ut, &mut idents);
return idents;
idents
} else {
self.kind.ident().into_iter().collect()
}
if let Some(ident) = self.kind.ident() { vec![ident] } else { vec![] }
}
}

View file

@ -360,6 +360,8 @@ declare_features! (
(accepted, relaxed_adts, "1.19.0", Some(35626)),
/// Lessens the requirements for structs to implement `Unsize`.
(accepted, relaxed_struct_unsize, "1.58.0", Some(81793)),
/// Allows the `#[repr(i128)]` attribute for enums.
(accepted, repr128, "CURRENT_RUSTC_VERSION", Some(56071)),
/// Allows `repr(align(16))` struct attribute (RFC 1358).
(accepted, repr_align, "1.25.0", Some(33626)),
/// Allows using `#[repr(align(X))]` on enums with equivalent semantics

View file

@ -621,8 +621,6 @@ declare_features! (
(incomplete, ref_pat_eat_one_layer_2024_structural, "1.81.0", Some(123076)),
/// Allows using the `#[register_tool]` attribute.
(unstable, register_tool, "1.41.0", Some(66079)),
/// Allows the `#[repr(i128)]` attribute for enums.
(incomplete, repr128, "1.16.0", Some(56071)),
/// Allows `repr(simd)` and importing the various simd intrinsics.
(unstable, repr_simd, "1.4.0", Some(27731)),
/// Allows bounding the return type of AFIT/RPITIT.

View file

@ -18,7 +18,7 @@ use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::error::TypeErrorToStringExt;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::util::Discr;
use rustc_middle::ty::{
AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, fold_regions,
@ -1385,19 +1385,6 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
);
}
let repr_type_ty = def.repr().discr_type().to_ty(tcx);
if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
if !tcx.features().repr128() {
feature_err(
&tcx.sess,
sym::repr128,
tcx.def_span(def_id),
"repr with 128-bit type is unstable",
)
.emit();
}
}
for v in def.variants() {
if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
tcx.ensure_ok().typeck(discr_def_id.expect_local());

View file

@ -298,11 +298,9 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
check_item_fn(tcx, def_id, ident, item.span, sig.decl)
}
hir::ItemKind::Static(_, ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Const(_, ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
check_static_item(tcx, def_id, ty.span, UnsizedHandling::Forbid)
}
hir::ItemKind::Const(_, ty, ..) => check_const_item(tcx, def_id, ty.span, item.span),
hir::ItemKind::Struct(_, _, hir_generics) => {
let res = check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, hir_generics);
@ -366,7 +364,7 @@ fn check_foreign_item<'tcx>(
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl)
}
hir::ForeignItemKind::Static(ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
check_static_item(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
}
hir::ForeignItemKind::Type => Ok(()),
}
@ -1048,8 +1046,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
match ty.kind() {
ty::Adt(adt_def, ..) => adt_def.did().is_local(),
// Arrays and slices use the inner type's `ConstParamTy`.
ty::Array(ty, ..) => ty_is_local(*ty),
ty::Slice(ty) => ty_is_local(*ty),
ty::Array(ty, ..) | ty::Slice(ty) => ty_is_local(*ty),
// `&` references use the inner type's `ConstParamTy`.
// `&mut` are not supported.
ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty),
@ -1331,14 +1328,13 @@ enum UnsizedHandling {
AllowIfForeignTail,
}
fn check_item_type(
#[instrument(level = "debug", skip(tcx, ty_span, unsized_handling))]
fn check_static_item(
tcx: TyCtxt<'_>,
item_id: LocalDefId,
ty_span: Span,
unsized_handling: UnsizedHandling,
) -> Result<(), ErrorGuaranteed> {
debug!("check_item_type: {:?}", item_id);
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
let ty = tcx.type_of(item_id).instantiate_identity();
let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
@ -1388,6 +1384,34 @@ fn check_item_type(
})
}
fn check_const_item(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
ty_span: Span,
item_span: Span,
) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, ty_span, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into());
wfcx.register_bound(
traits::ObligationCause::new(
ty_span,
wfcx.body_def_id,
ObligationCauseCode::SizedConstOrStatic,
),
wfcx.param_env,
ty,
tcx.require_lang_item(LangItem::Sized, None),
);
check_where_clauses(wfcx, item_span, def_id);
Ok(())
})
}
#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))]
fn check_impl<'tcx>(
tcx: TyCtxt<'tcx>,

View file

@ -203,7 +203,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
tcx.ensure_ok().eval_static_initializer(item_def_id);
check::maybe_check_static_with_link_section(tcx, item_def_id);
}
DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
DefKind::Const if !tcx.generics_of(item_def_id).own_requires_monomorphization() => {
// FIXME(generic_const_items): Passing empty instead of identity args is fishy but
// seems to be fine for now. Revisit this!
let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty());
let cid = GlobalId { instance, promoted: None };
let typing_env = ty::TypingEnv::fully_monomorphized();

View file

@ -1793,10 +1793,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let element_ty = if !args.is_empty() {
let coerce_to = expected
.to_option(self)
.and_then(|uty| match *self.try_structurally_resolve_type(expr.span, uty).kind() {
ty::Array(ty, _) | ty::Slice(ty) => Some(ty),
_ => None,
})
.and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index())
.unwrap_or_else(|| self.next_ty_var(expr.span));
let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
assert_eq!(self.diverges.get(), Diverges::Maybe);
@ -1874,10 +1871,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let uty = match expected {
ExpectHasType(uty) => match *uty.kind() {
ty::Array(ty, _) | ty::Slice(ty) => Some(ty),
_ => None,
},
ExpectHasType(uty) => uty.builtin_index(),
_ => None,
};

View file

@ -497,6 +497,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
if p.flags().intersects(self.needs_canonical_flags) { p.super_fold_with(self) } else { p }
}
fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
if c.flags().intersects(self.needs_canonical_flags) { c.super_fold_with(self) } else { c }
}
}
impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {

View file

@ -55,6 +55,14 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
ct.super_fold_with(self)
}
}
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
if !p.has_non_region_infer() { p } else { p.super_fold_with(self) }
}
fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
if !c.has_non_region_infer() { c } else { c.super_fold_with(self) }
}
}
/// The opportunistic region resolver opportunistically resolves regions

View file

@ -512,7 +512,7 @@ impl Allocation {
pub fn adjust_from_tcx<'tcx, Prov: Provenance, Bytes: AllocBytes>(
&self,
cx: &impl HasDataLayout,
mut alloc_bytes: impl FnMut(&[u8], Align) -> InterpResult<'tcx, Bytes>,
alloc_bytes: impl FnOnce(&[u8], Align) -> InterpResult<'tcx, Bytes>,
mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> InterpResult<'tcx, Pointer<Prov>>,
) -> InterpResult<'tcx, Allocation<Prov, (), Bytes>> {
// Copy the data.

View file

@ -9,7 +9,6 @@ use super::{
ReportedErrorInfo,
};
use crate::mir;
use crate::query::TyCtxtEnsureOk;
use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt};
impl<'tcx> TyCtxt<'tcx> {
@ -197,24 +196,3 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
}
impl<'tcx> TyCtxtEnsureOk<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
/// that can't take any generic arguments like const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) {
// In some situations def_id will have generic parameters within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
// encountered.
let args = GenericArgs::identity_for_item(self.tcx, def_id);
let instance = ty::Instance::new_raw(def_id, self.tcx.erase_regions(args));
let cid = GlobalId { instance, promoted: None };
let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id);
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.tcx.erase_regions(typing_env.as_query_input(cid));
self.eval_to_const_value_raw(inputs)
}
}

View file

@ -117,6 +117,10 @@ impl<'tcx> CapturedPlace<'tcx> {
}
},
HirProjectionKind::UnwrapUnsafeBinder => {
write!(&mut symbol, "__unwrap").unwrap();
}
// Ignore derefs for now, as they are likely caused by
// autoderefs that don't appear in the original code.
HirProjectionKind::Deref => {}

View file

@ -86,4 +86,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
p
}
}
fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
if c.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) {
c.super_fold_with(self)
} else {
c
}
}
}

View file

@ -177,6 +177,10 @@ where
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
}
fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c }
}
}
impl<'tcx> TyCtxt<'tcx> {

View file

@ -238,6 +238,8 @@ impl<'tcx> Clause<'tcx> {
}
}
impl<'tcx> rustc_type_ir::inherent::Clauses<TyCtxt<'tcx>> for ty::Clauses<'tcx> {}
#[extension(pub trait ExistentialPredicateStableCmpExt<'tcx>)]
impl<'tcx> ExistentialPredicate<'tcx> {
/// Compares via an ordering that will not change if modules are reordered or other changes are

View file

@ -570,6 +570,19 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clause<'tcx> {
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clauses<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
folder.try_fold_clauses(self)
}
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
folder.fold_clauses(self)
}
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
visitor.visit_predicate(*self)
@ -615,6 +628,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Clauses<'tcx> {
}
}
impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Clauses<'tcx> {
fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_clauses(v))
}
fn super_fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v))
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
@ -775,7 +801,6 @@ macro_rules! list_fold {
}
list_fold! {
ty::Clauses<'tcx> : mk_clauses,
&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> : mk_poly_existential_predicates,
&'tcx ty::List<PlaceElem<'tcx>> : mk_place_elems,
&'tcx ty::List<ty::Pattern<'tcx>> : mk_patterns,

View file

@ -101,12 +101,12 @@ fn convert_to_hir_projections_and_truncate_for_capture(
variant = Some(*idx);
continue;
}
ProjectionElem::UnwrapUnsafeBinder(_) => HirProjectionKind::UnwrapUnsafeBinder,
// These do not affect anything, they just make sure we know the right type.
ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {
| ProjectionElem::Subslice { .. } => {
// We don't capture array-access projections.
// We can stop here as arrays are captured completely.
break;

View file

@ -209,7 +209,7 @@ const ROOT_NODE: DropIdx = DropIdx::ZERO;
#[derive(Debug)]
struct DropTree {
/// Nodes in the drop tree, containing drop data and a link to the next node.
drops: IndexVec<DropIdx, DropNode>,
drop_nodes: IndexVec<DropIdx, DropNode>,
/// Map for finding the index of an existing node, given its contents.
existing_drops_map: FxHashMap<DropNodeKey, DropIdx>,
/// Edges into the `DropTree` that need to be added once it's lowered.
@ -230,7 +230,6 @@ struct DropNode {
struct DropNodeKey {
next: DropIdx,
local: Local,
kind: DropKind,
}
impl Scope {
@ -278,8 +277,8 @@ impl DropTree {
let fake_source_info = SourceInfo::outermost(DUMMY_SP);
let fake_data =
DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]);
Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() }
let drop_nodes = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]);
Self { drop_nodes, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() }
}
/// Adds a node to the drop tree, consisting of drop data and the index of
@ -288,12 +287,12 @@ impl DropTree {
/// If there is already an equivalent node in the tree, nothing is added, and
/// that node's index is returned. Otherwise, the new node's index is returned.
fn add_drop(&mut self, data: DropData, next: DropIdx) -> DropIdx {
let drops = &mut self.drops;
let drop_nodes = &mut self.drop_nodes;
*self
.existing_drops_map
.entry(DropNodeKey { next, local: data.local, kind: data.kind })
.entry(DropNodeKey { next, local: data.local })
// Create a new node, and also add its index to the map.
.or_insert_with(|| drops.push(DropNode { data, next }))
.or_insert_with(|| drop_nodes.push(DropNode { data, next }))
}
/// Registers `from` as an entry point to this drop tree, at `to`.
@ -301,7 +300,7 @@ impl DropTree {
/// During [`Self::build_mir`], `from` will be linked to the corresponding
/// block within the drop tree.
fn add_entry_point(&mut self, from: BasicBlock, to: DropIdx) {
debug_assert!(to < self.drops.next_index());
debug_assert!(to < self.drop_nodes.next_index());
self.entry_points.push((to, from));
}
@ -341,10 +340,10 @@ impl DropTree {
Own,
}
let mut blocks = IndexVec::from_elem(None, &self.drops);
let mut blocks = IndexVec::from_elem(None, &self.drop_nodes);
blocks[ROOT_NODE] = root_node;
let mut needs_block = IndexVec::from_elem(Block::None, &self.drops);
let mut needs_block = IndexVec::from_elem(Block::None, &self.drop_nodes);
if root_node.is_some() {
// In some cases (such as drops for `continue`) the root node
// already has a block. In this case, make sure that we don't
@ -356,7 +355,7 @@ impl DropTree {
let entry_points = &mut self.entry_points;
entry_points.sort();
for (drop_idx, drop_node) in self.drops.iter_enumerated().rev() {
for (drop_idx, drop_node) in self.drop_nodes.iter_enumerated().rev() {
if entry_points.last().is_some_and(|entry_point| entry_point.0 == drop_idx) {
let block = *blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
needs_block[drop_idx] = Block::Own;
@ -396,7 +395,7 @@ impl DropTree {
cfg: &mut CFG<'tcx>,
blocks: &IndexSlice<DropIdx, Option<BasicBlock>>,
) {
for (drop_idx, drop_node) in self.drops.iter_enumerated().rev() {
for (drop_idx, drop_node) in self.drop_nodes.iter_enumerated().rev() {
let Some(block) = blocks[drop_idx] else { continue };
match drop_node.data.kind {
DropKind::Value => {
@ -726,11 +725,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
drops
};
let drop_idx = self.scopes.scopes[scope_index + 1..]
.iter()
.flat_map(|scope| &scope.drops)
.fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx));
let mut drop_idx = ROOT_NODE;
for scope in &self.scopes.scopes[scope_index + 1..] {
for drop in &scope.drops {
drop_idx = drops.add_drop(*drop, drop_idx);
}
}
drops.add_entry_point(block, drop_idx);
// `build_drop_trees` doesn't have access to our source_info, so we
@ -829,9 +829,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// `unwind_to` should drop the value that we're about to
// schedule. If dropping this value panics, then we continue
// with the *next* value on the unwind path.
debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
unwind_to = unwind_drops.drops[unwind_to].next;
debug_assert_eq!(
unwind_drops.drop_nodes[unwind_to].data.local,
drop_data.local
);
debug_assert_eq!(
unwind_drops.drop_nodes[unwind_to].data.kind,
drop_data.kind
);
unwind_to = unwind_drops.drop_nodes[unwind_to].next;
let mut unwind_entry_point = unwind_to;
@ -1551,14 +1557,14 @@ where
//
// We adjust this BEFORE we create the drop (e.g., `drops[n]`)
// because `drops[n]` should unwind to `drops[n-1]`.
debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
unwind_to = unwind_drops.drops[unwind_to].next;
debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.local, drop_data.local);
debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.kind, drop_data.kind);
unwind_to = unwind_drops.drop_nodes[unwind_to].next;
if let Some(idx) = dropline_to {
debug_assert_eq!(coroutine_drops.drops[idx].data.local, drop_data.local);
debug_assert_eq!(coroutine_drops.drops[idx].data.kind, drop_data.kind);
dropline_to = Some(coroutine_drops.drops[idx].next);
debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.local, drop_data.local);
debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.kind, drop_data.kind);
dropline_to = Some(coroutine_drops.drop_nodes[idx].next);
}
// If the operand has been moved, and we are not on an unwind
@ -1598,9 +1604,12 @@ where
// cases we emit things ALSO on the unwind path, so we need to adjust
// `unwind_to` in that case.
if storage_dead_on_unwind {
debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
unwind_to = unwind_drops.drops[unwind_to].next;
debug_assert_eq!(
unwind_drops.drop_nodes[unwind_to].data.local,
drop_data.local
);
debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.kind, drop_data.kind);
unwind_to = unwind_drops.drop_nodes[unwind_to].next;
}
// If the operand has been moved, and we are not on an unwind
@ -1629,14 +1638,17 @@ where
// the storage-dead has completed, we need to adjust the `unwind_to` pointer
// so that any future drops we emit will not register storage-dead.
if storage_dead_on_unwind {
debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
unwind_to = unwind_drops.drops[unwind_to].next;
debug_assert_eq!(
unwind_drops.drop_nodes[unwind_to].data.local,
drop_data.local
);
debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.kind, drop_data.kind);
unwind_to = unwind_drops.drop_nodes[unwind_to].next;
}
if let Some(idx) = dropline_to {
debug_assert_eq!(coroutine_drops.drops[idx].data.local, drop_data.local);
debug_assert_eq!(coroutine_drops.drops[idx].data.kind, drop_data.kind);
dropline_to = Some(coroutine_drops.drops[idx].next);
debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.local, drop_data.local);
debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.kind, drop_data.kind);
dropline_to = Some(coroutine_drops.drop_nodes[idx].next);
}
// Only temps and vars need their storage dead.
assert!(local.index() > arg_count);
@ -1663,10 +1675,10 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
let is_coroutine = self.coroutine.is_some();
// Link the exit drop tree to unwind drop tree.
if drops.drops.iter().any(|drop_node| drop_node.data.kind == DropKind::Value) {
if drops.drop_nodes.iter().any(|drop_node| drop_node.data.kind == DropKind::Value) {
let unwind_target = self.diverge_cleanup_target(else_scope, span);
let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
for (drop_idx, drop_node) in drops.drops.iter_enumerated().skip(1) {
for (drop_idx, drop_node) in drops.drop_nodes.iter_enumerated().skip(1) {
match drop_node.data.kind {
DropKind::Storage | DropKind::ForLint => {
if is_coroutine {
@ -1695,35 +1707,29 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
}
// Link the exit drop tree to dropline drop tree (coroutine drop path) for async drops
if is_coroutine
&& drops.drops.iter().any(|DropNode { data, next: _ }| {
&& drops.drop_nodes.iter().any(|DropNode { data, next: _ }| {
data.kind == DropKind::Value && self.is_async_drop(data.local)
})
{
let dropline_target = self.diverge_dropline_target(else_scope, span);
let mut dropline_indices = IndexVec::from_elem_n(dropline_target, 1);
for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) {
for (drop_idx, drop_data) in drops.drop_nodes.iter_enumerated().skip(1) {
let coroutine_drop = self
.scopes
.coroutine_drops
.add_drop(drop_data.data, dropline_indices[drop_data.next]);
match drop_data.data.kind {
DropKind::Storage | DropKind::ForLint => {
let coroutine_drop = self
.scopes
.coroutine_drops
.add_drop(drop_data.data, dropline_indices[drop_data.next]);
dropline_indices.push(coroutine_drop);
}
DropKind::Storage | DropKind::ForLint => {}
DropKind::Value => {
let coroutine_drop = self
.scopes
.coroutine_drops
.add_drop(drop_data.data, dropline_indices[drop_data.next]);
if self.is_async_drop(drop_data.data.local) {
self.scopes.coroutine_drops.add_entry_point(
blocks[drop_idx].unwrap(),
dropline_indices[drop_data.next],
);
}
dropline_indices.push(coroutine_drop);
}
}
dropline_indices.push(coroutine_drop);
}
}
blocks[ROOT_NODE].map(BasicBlock::unit)
@ -1769,11 +1775,11 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
// prevent drop elaboration from creating drop flags that would have
// to be captured by the coroutine. I'm not sure how important this
// optimization is, but it is here.
for (drop_idx, drop_node) in drops.drops.iter_enumerated() {
for (drop_idx, drop_node) in drops.drop_nodes.iter_enumerated() {
if let DropKind::Value = drop_node.data.kind
&& let Some(bb) = blocks[drop_idx]
{
debug_assert!(drop_node.next < drops.drops.next_index());
debug_assert!(drop_node.next < drops.drop_nodes.next_index());
drops.entry_points.push((drop_node.next, bb));
}
}

View file

@ -1483,7 +1483,7 @@ impl<'v> RootCollector<'_, 'v> {
// But even just declaring them must collect the items they refer to
// unless their generics require monomorphization.
if !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx)
if !self.tcx.generics_of(id.owner_id).own_requires_monomorphization()
&& let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id())
{
collect_const_value(self.tcx, val, self.output);

View file

@ -572,4 +572,15 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
if p.flags().intersects(NEEDS_CANONICAL) { p.super_fold_with(self) } else { p }
}
fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
match self.canonicalize_mode {
CanonicalizeMode::Input { keep_static: true }
| CanonicalizeMode::Response { max_input_universe: _ } => {}
CanonicalizeMode::Input { keep_static: false } => {
panic!("erasing 'static in env")
}
}
if c.flags().intersects(NEEDS_CANONICAL) { c.super_fold_with(self) } else { c }
}
}

View file

@ -11,7 +11,7 @@ use crate::delegate::SolverDelegate;
// EAGER RESOLUTION
/// Resolves ty, region, and const vars to their inferred values or their root vars.
pub struct EagerResolver<'a, D, I = <D as SolverDelegate>::Interner>
struct EagerResolver<'a, D, I = <D as SolverDelegate>::Interner>
where
D: SolverDelegate<Interner = I>,
I: Interner,
@ -22,8 +22,20 @@ where
cache: DelayedMap<I::Ty, I::Ty>,
}
pub fn eager_resolve_vars<D: SolverDelegate, T: TypeFoldable<D::Interner>>(
delegate: &D,
value: T,
) -> T {
if value.has_infer() {
let mut folder = EagerResolver::new(delegate);
value.fold_with(&mut folder)
} else {
value
}
}
impl<'a, D: SolverDelegate> EagerResolver<'a, D> {
pub fn new(delegate: &'a D) -> Self {
fn new(delegate: &'a D) -> Self {
EagerResolver { delegate, cache: Default::default() }
}
}
@ -90,4 +102,8 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolv
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
if p.has_infer() { p.super_fold_with(self) } else { p }
}
fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
if c.has_infer() { c.super_fold_with(self) } else { c }
}
}

View file

@ -22,7 +22,7 @@ use tracing::{debug, instrument, trace};
use crate::canonicalizer::Canonicalizer;
use crate::delegate::SolverDelegate;
use crate::resolve::EagerResolver;
use crate::resolve::eager_resolve_vars;
use crate::solve::eval_ctxt::CurrentGoalKind;
use crate::solve::{
CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal,
@ -61,8 +61,7 @@ where
// so we only canonicalize the lookup table and ignore
// duplicate entries.
let opaque_types = self.delegate.clone_opaque_types_lookup_table();
let (goal, opaque_types) =
(goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate));
let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types));
let mut orig_values = Default::default();
let canonical = Canonicalizer::canonicalize_input(
@ -162,8 +161,8 @@ where
let external_constraints =
self.compute_external_query_constraints(certainty, normalization_nested_goals);
let (var_values, mut external_constraints) = (self.var_values, external_constraints)
.fold_with(&mut EagerResolver::new(self.delegate));
let (var_values, mut external_constraints) =
eager_resolve_vars(self.delegate, (self.var_values, external_constraints));
// Remove any trivial or duplicated region constraints once we've resolved regions
let mut unique = HashSet::default();
@ -474,7 +473,7 @@ where
{
let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) };
let state = inspect::State { var_values, data };
let state = state.fold_with(&mut EagerResolver::new(delegate));
let state = eager_resolve_vars(delegate, state);
Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut vec![], state)
}

View file

@ -925,6 +925,22 @@ where
}
}
}
fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result {
if p.has_non_region_infer() || p.has_placeholders() {
p.super_visit_with(self)
} else {
ControlFlow::Continue(())
}
}
fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result {
if c.has_non_region_infer() || c.has_placeholders() {
c.super_visit_with(self)
} else {
ControlFlow::Continue(())
}
}
}
let mut visitor = ContainsTermOrNotNameable {

View file

@ -1577,7 +1577,7 @@ impl<'a> Parser<'a> {
};
let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
Ok(ItemKind::Enum(ident, enum_definition, generics))
Ok(ItemKind::Enum(ident, generics, enum_definition))
}
fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> {
@ -1732,7 +1732,7 @@ impl<'a> Parser<'a> {
return Err(self.dcx().create_err(err));
};
Ok(ItemKind::Struct(ident, vdata, generics))
Ok(ItemKind::Struct(ident, generics, vdata))
}
/// Parses `union Foo { ... }`.
@ -1764,7 +1764,7 @@ impl<'a> Parser<'a> {
return Err(err);
};
Ok(ItemKind::Union(ident, vdata, generics))
Ok(ItemKind::Union(ident, generics, vdata))
}
/// This function parses the fields of record structs:

View file

@ -515,8 +515,8 @@ impl<'a> Parser<'a> {
fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
let prev = self.prev_token.span;
let sp = self.token.span;
let mut e = self.dcx().struct_span_err(sp, msg);
self.label_expected_raw_ref(&mut e);
let mut err = self.dcx().struct_span_err(sp, msg);
self.label_expected_raw_ref(&mut err);
let do_not_suggest_help = self.token.is_keyword(kw::In)
|| self.token == token::Colon
@ -558,20 +558,19 @@ impl<'a> Parser<'a> {
stmt.span
};
self.suggest_fixes_misparsed_for_loop_head(
&mut e,
&mut err,
prev.between(sp),
stmt_span,
&stmt.kind,
);
}
Err(e) => {
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
e.cancel();
e.delay_as_bug();
}
_ => {}
}
e.span_label(sp, "expected `{`");
e
err.span_label(sp, "expected `{`");
err
}
fn suggest_fixes_misparsed_for_loop_head(

View file

@ -255,7 +255,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_generic_attr(hir_id, attr, target, Target::Fn);
self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
}
[sym::autodiff, ..] => {
[sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
self.check_autodiff(hir_id, attr, span, target)
}
[sym::coroutine, ..] => {

View file

@ -249,12 +249,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)),
_ => bug!("Unexpected type for `Ref` constructor: {ty:?}"),
},
Slice(slice) => match *ty.kind() {
ty::Slice(ty) | ty::Array(ty, _) => {
Slice(slice) => match ty.builtin_index() {
Some(ty) => {
let arity = slice.arity();
reveal_and_alloc(cx, (0..arity).map(|_| ty))
}
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
None => bug!("bad slice pattern {:?} {:?}", ctor, ty),
},
DerefPattern(pointee_ty) => reveal_and_alloc(cx, once(pointee_ty.inner())),
Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)

View file

@ -823,7 +823,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
// These items live in both the type and value namespaces.
ItemKind::Struct(ident, ref vdata, _) => {
ItemKind::Struct(ident, _, ref vdata) => {
self.build_reduced_graph_for_struct_variant(
vdata.fields(),
ident,
@ -874,7 +874,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
}
ItemKind::Union(ident, ref vdata, _) => {
ItemKind::Union(ident, _, ref vdata) => {
self.build_reduced_graph_for_struct_variant(
vdata.fields(),
ident,

View file

@ -162,8 +162,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
self.with_parent(def_id, |this| {
this.with_impl_trait(ImplTraitContext::Existential, |this| {
match i.kind {
ItemKind::Struct(_, ref struct_def, _)
| ItemKind::Union(_, ref struct_def, _) => {
ItemKind::Struct(_, _, ref struct_def)
| ItemKind::Union(_, _, ref struct_def) => {
// If this is a unit or tuple-like struct, register the constructor.
if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) {
this.create_def(

View file

@ -6,7 +6,7 @@ use rustc_ast::{
};
use rustc_ast_pretty::pprust;
use rustc_attr_data_structures::{self as attr, Stability};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{
@ -2623,7 +2623,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
};
for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols {
if parent_module != module || ident.name != *segment {
if ident.name != *segment {
continue;
}
fn comes_from_same_module_for_glob(
r: &Resolver<'_, '_>,
parent_module: DefId,
module: DefId,
visited: &mut FxHashMap<DefId, bool>,
) -> bool {
if let Some(&cached) = visited.get(&parent_module) {
// this branch is prevent from being called recursively infinity,
// because there has some cycles in globs imports,
// see more spec case at `tests/ui/cfg/diagnostics-reexport-2.rs#reexport32`
return cached;
}
visited.insert(parent_module, false);
let res = r.module_map.get(&parent_module).is_some_and(|m| {
for importer in m.glob_importers.borrow().iter() {
if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id()
{
if next_parent_module == module
|| comes_from_same_module_for_glob(
r,
next_parent_module,
module,
visited,
)
{
return true;
}
}
}
false
});
visited.insert(parent_module, res);
res
}
let comes_from_same_module = parent_module == module
|| comes_from_same_module_for_glob(
self,
parent_module,
module,
&mut Default::default(),
);
if !comes_from_same_module {
continue;
}

View file

@ -252,7 +252,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx>
self.current_private_vis = prev_private_vis;
}
ast::ItemKind::Enum(_, EnumDef { ref variants }, _) => {
ast::ItemKind::Enum(_, _, EnumDef { ref variants }) => {
self.set_bindings_effective_visibilities(def_id);
for variant in variants {
let variant_def_id = self.r.local_def_id(variant.id);
@ -262,7 +262,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx>
}
}
ast::ItemKind::Struct(_, ref def, _) | ast::ItemKind::Union(_, ref def, _) => {
ast::ItemKind::Struct(_, _, ref def) | ast::ItemKind::Union(_, _, ref def) => {
for field in def.fields() {
self.update_field(self.r.local_def_id(field.id), def_id);
}

View file

@ -2694,9 +2694,9 @@ impl<'a, 'ast, 'ra: 'ast, '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(_, ref generics, _)
| ItemKind::Struct(_, ref generics, _)
| ItemKind::Union(_, ref generics, _) => {
self.resolve_adt(item, generics);
}
@ -5243,9 +5243,9 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
ItemKind::TyAlias(box TyAlias { generics, .. })
| ItemKind::Const(box ConstItem { generics, .. })
| ItemKind::Fn(box Fn { generics, .. })
| ItemKind::Enum(_, _, generics)
| ItemKind::Struct(_, _, generics)
| ItemKind::Union(_, _, generics)
| ItemKind::Enum(_, generics, _)
| ItemKind::Struct(_, generics, _)
| ItemKind::Union(_, generics, _)
| ItemKind::Impl(box Impl { generics, .. })
| ItemKind::Trait(box Trait { generics, .. })
| ItemKind::TraitAlias(_, generics, _) => {

View file

@ -244,6 +244,7 @@ symbols! {
FnMut,
FnOnce,
Formatter,
Forward,
From,
FromIterator,
FromResidual,
@ -339,6 +340,7 @@ symbols! {
Result,
ResumeTy,
Return,
Reverse,
Right,
Rust,
RustaceansAreAwesome,
@ -522,7 +524,8 @@ symbols! {
audit_that,
augmented_assignments,
auto_traits,
autodiff,
autodiff_forward,
autodiff_reverse,
automatically_derived,
avx,
avx10_target_feature,
@ -2071,6 +2074,9 @@ symbols! {
sym,
sync,
synthetic,
sys_mutex_lock,
sys_mutex_try_lock,
sys_mutex_unlock,
t32,
target,
target_abi,

View file

@ -15,9 +15,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_macros::extension;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
use rustc_middle::ty::{TyCtxt, TypeFoldable, VisitorResult, try_visit};
use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit};
use rustc_middle::{bug, ty};
use rustc_next_trait_solver::resolve::EagerResolver;
use rustc_next_trait_solver::resolve::eager_resolve_vars;
use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _};
use rustc_span::{DUMMY_SP, Span};
@ -187,8 +187,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
let _ = term_hack.constrain(infcx, span, param_env);
}
let opt_impl_args =
opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx)));
let opt_impl_args = opt_impl_args.map(|impl_args| eager_resolve_vars(infcx, impl_args));
let goals = instantiated_goals
.into_iter()
@ -392,7 +391,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
infcx,
depth,
orig_values,
goal: uncanonicalized_goal.fold_with(&mut EagerResolver::new(infcx)),
goal: eager_resolve_vars(infcx, uncanonicalized_goal),
result,
evaluation_kind: evaluation.kind,
normalizes_to_term_hack,

View file

@ -711,6 +711,14 @@ impl<'a, I: Interner> TypeFolder<I> for ArgFolder<'a, I> {
c.super_fold_with(self)
}
}
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
if p.has_param() { p.super_fold_with(self) } else { p }
}
fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
if c.has_param() { c.super_fold_with(self) } else { c }
}
}
impl<'a, I: Interner> ArgFolder<'a, I> {

View file

@ -152,6 +152,10 @@ pub trait TypeFolder<I: Interner>: Sized {
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
p.super_fold_with(self)
}
fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
c.super_fold_with(self)
}
}
/// This trait is implemented for every folding traversal. There is a fold
@ -190,6 +194,10 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
p.try_super_fold_with(self)
}
fn try_fold_clauses(&mut self, c: I::Clauses) -> Result<I::Clauses, Self::Error> {
c.try_super_fold_with(self)
}
}
///////////////////////////////////////////////////////////////////////////

View file

@ -511,6 +511,18 @@ pub trait Clause<I: Interner<Clause = Self>>:
fn instantiate_supertrait(self, cx: I, trait_ref: ty::Binder<I, ty::TraitRef<I>>) -> Self;
}
pub trait Clauses<I: Interner<Clauses = Self>>:
Copy
+ Debug
+ Hash
+ Eq
+ TypeSuperVisitable<I>
+ TypeSuperFoldable<I>
+ Flags
+ SliceLike<Item = I::Clause>
{
}
/// Common capabilities of placeholder kinds
pub trait PlaceholderLike: Copy + Debug + Hash + Eq {
fn universe(self) -> ty::UniverseIndex;

View file

@ -12,7 +12,7 @@ use crate::ir_print::IrPrint;
use crate::lang_items::TraitSolverLangItem;
use crate::relate::Relate;
use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::visit::{Flags, TypeVisitable};
use crate::{self as ty, search_graph};
#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_interner")]
@ -146,7 +146,7 @@ pub trait Interner:
type ParamEnv: ParamEnv<Self>;
type Predicate: Predicate<Self>;
type Clause: Clause<Self>;
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
type Clauses: Clauses<Self>;
fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R;

View file

@ -120,8 +120,8 @@ pub trait TypeVisitor<I: Interner>: Sized {
p.super_visit_with(self)
}
fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result {
p.super_visit_with(self)
fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result {
c.super_visit_with(self)
}
fn visit_error(&mut self, _guar: I::ErrorGuaranteed) -> Self::Result {

View file

@ -632,6 +632,30 @@ impl CStr {
// instead of doing it afterwards.
str::from_utf8(self.to_bytes())
}
/// Returns an object that implements [`Display`] for safely printing a [`CStr`] that may
/// contain non-Unicode data.
///
/// Behaves as if `self` were first lossily converted to a `str`, with invalid UTF-8 presented
/// as the Unicode replacement character: <20>.
///
/// [`Display`]: fmt::Display
///
/// # Examples
///
/// ```
/// #![feature(cstr_display)]
///
/// let cstr = c"Hello, world!";
/// println!("{}", cstr.display());
/// ```
#[unstable(feature = "cstr_display", issue = "139984")]
#[must_use = "this does not display the `CStr`; \
it returns an object that can be displayed"]
#[inline]
pub fn display(&self) -> impl fmt::Display {
crate::bstr::ByteStr::from_bytes(self.to_bytes())
}
}
// `.to_bytes()` representations are compared instead of the inner `[c_char]`s,

View file

@ -225,10 +225,11 @@ pub mod assert_matches {
// We don't export this through #[macro_export] for now, to avoid breakage.
#[unstable(feature = "autodiff", issue = "124509")]
#[cfg(not(bootstrap))]
/// Unstable module containing the unstable `autodiff` macro.
pub mod autodiff {
#[unstable(feature = "autodiff", issue = "124509")]
pub use crate::macros::builtin::autodiff;
pub use crate::macros::builtin::{autodiff_forward, autodiff_reverse};
}
#[unstable(feature = "contracts", issue = "128044")]

View file

@ -1519,20 +1519,41 @@ pub(crate) mod builtin {
($file:expr $(,)?) => {{ /* compiler built-in */ }};
}
/// Automatic Differentiation macro which allows generating a new function to compute
/// the derivative of a given function. It may only be applied to a function.
/// The expected usage syntax is
/// `#[autodiff(NAME, MODE, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]`
/// where:
/// NAME is a string that represents a valid function name.
/// MODE is any of Forward, Reverse, ForwardFirst, ReverseFirst.
/// INPUT_ACTIVITIES consists of one valid activity for each input parameter.
/// OUTPUT_ACTIVITY must not be set if we implicitly return nothing (or explicitly return
/// `-> ()`). Otherwise it must be set to one of the allowed activities.
/// This macro uses forward-mode automatic differentiation to generate a new function.
/// It may only be applied to a function. The new function will compute the derivative
/// of the function to which the macro was applied.
///
/// The expected usage syntax is:
/// `#[autodiff_forward(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]`
///
/// - `NAME`: A string that represents a valid function name.
/// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter.
/// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing
/// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities.
#[unstable(feature = "autodiff", issue = "124509")]
#[allow_internal_unstable(rustc_attrs)]
#[rustc_builtin_macro]
pub macro autodiff($item:item) {
#[cfg(not(bootstrap))]
pub macro autodiff_forward($item:item) {
/* compiler built-in */
}
/// This macro uses reverse-mode automatic differentiation to generate a new function.
/// It may only be applied to a function. The new function will compute the derivative
/// of the function to which the macro was applied.
///
/// The expected usage syntax is:
/// `#[autodiff_reverse(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]`
///
/// - `NAME`: A string that represents a valid function name.
/// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter.
/// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing
/// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities.
#[unstable(feature = "autodiff", issue = "124509")]
#[allow_internal_unstable(rustc_attrs)]
#[rustc_builtin_macro]
#[cfg(not(bootstrap))]
pub macro autodiff_reverse($item:item) {
/* compiler built-in */
}

View file

@ -131,6 +131,8 @@ phantom_lifetime! {
///
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
///
/// Note: If `'a` is otherwise contravariant or invariant, the resulting type is invariant.
///
/// ## Layout
///
/// For all `'a`, the following are guaranteed:
@ -146,6 +148,8 @@ phantom_lifetime! {
///
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
///
/// Note: If `'a` is otherwise covariant or invariant, the resulting type is invariant.
///
/// ## Layout
///
/// For all `'a`, the following are guaranteed:
@ -180,6 +184,8 @@ phantom_type! {
///
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
///
/// Note: If `T` is otherwise contravariant or invariant, the resulting type is invariant.
///
/// ## Layout
///
/// For all `T`, the following are guaranteed:
@ -196,6 +202,8 @@ phantom_type! {
///
/// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
///
/// Note: If `T` is otherwise covariant or invariant, the resulting type is invariant.
///
/// ## Layout
///
/// For all `T`, the following are guaranteed:

View file

@ -3885,10 +3885,13 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
}
}
/// Publicly exposed for stdarch; nobody else should use this.
#[inline]
#[cfg(target_has_atomic)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn atomic_compare_exchange<T: Copy>(
#[unstable(feature = "core_intrinsics", issue = "none")]
#[doc(hidden)]
pub unsafe fn atomic_compare_exchange<T: Copy>(
dst: *mut T,
old: T,
new: T,

View file

@ -19,3 +19,9 @@ fn debug() {
let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF";
assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
}
#[test]
fn display() {
let s = c"\xf0\x28\x8c\xbc";
assert_eq!(format!("{}", s.display()), "<EFBFBD>(<28><>");
}

View file

@ -23,6 +23,7 @@
#![feature(core_io_borrowed_buf)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(cstr_display)]
#![feature(dec2flt)]
#![feature(duration_constants)]
#![feature(duration_constructors)]

View file

@ -732,7 +732,7 @@ assume_usize_width! {
}
macro_rules! test_float {
($modname: ident, $fassert: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => {
($modname: ident, $fassert: ident, $fty: ty) => {
mod $modname {
#[test]
fn min() {
@ -747,19 +747,19 @@ macro_rules! test_float {
$fassert!((-0.0 as $fty).min(9.0), -0.0);
$fassert!((-0.0 as $fty).min(9.0).is_sign_negative());
$fassert!((-0.0 as $fty).min(-9.0), -9.0);
$fassert!(($inf as $fty).min(9.0), 9.0);
$fassert!((9.0 as $fty).min($inf), 9.0);
$fassert!(($inf as $fty).min(-9.0), -9.0);
$fassert!((-9.0 as $fty).min($inf), -9.0);
$fassert!(($neginf as $fty).min(9.0), $neginf);
$fassert!((9.0 as $fty).min($neginf), $neginf);
$fassert!(($neginf as $fty).min(-9.0), $neginf);
$fassert!((-9.0 as $fty).min($neginf), $neginf);
$fassert!(($nan as $fty).min(9.0), 9.0);
$fassert!(($nan as $fty).min(-9.0), -9.0);
$fassert!((9.0 as $fty).min($nan), 9.0);
$fassert!((-9.0 as $fty).min($nan), -9.0);
$fassert!(($nan as $fty).min($nan).is_nan());
$fassert!(<$fty>::INFINITY.min(9.0), 9.0);
$fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0);
$fassert!(<$fty>::INFINITY.min(-9.0), -9.0);
$fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0);
$fassert!(<$fty>::NEG_INFINITY.min(9.0), <$fty>::NEG_INFINITY);
$fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY);
$fassert!(<$fty>::NEG_INFINITY.min(-9.0), <$fty>::NEG_INFINITY);
$fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY);
$fassert!(<$fty>::NAN.min(9.0), 9.0);
$fassert!(<$fty>::NAN.min(-9.0), -9.0);
$fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0);
$fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0);
$fassert!(<$fty>::NAN.min(<$fty>::NAN).is_nan());
}
#[test]
fn max() {
@ -777,19 +777,19 @@ macro_rules! test_float {
$fassert!((0.0 as $fty).max(-9.0).is_sign_positive());
$fassert!((-0.0 as $fty).max(-9.0), -0.0);
$fassert!((-0.0 as $fty).max(-9.0).is_sign_negative());
$fassert!(($inf as $fty).max(9.0), $inf);
$fassert!((9.0 as $fty).max($inf), $inf);
$fassert!(($inf as $fty).max(-9.0), $inf);
$fassert!((-9.0 as $fty).max($inf), $inf);
$fassert!(($neginf as $fty).max(9.0), 9.0);
$fassert!((9.0 as $fty).max($neginf), 9.0);
$fassert!(($neginf as $fty).max(-9.0), -9.0);
$fassert!((-9.0 as $fty).max($neginf), -9.0);
$fassert!(($nan as $fty).max(9.0), 9.0);
$fassert!(($nan as $fty).max(-9.0), -9.0);
$fassert!((9.0 as $fty).max($nan), 9.0);
$fassert!((-9.0 as $fty).max($nan), -9.0);
$fassert!(($nan as $fty).max($nan).is_nan());
$fassert!(<$fty>::INFINITY.max(9.0), <$fty>::INFINITY);
$fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY);
$fassert!(<$fty>::INFINITY.max(-9.0), <$fty>::INFINITY);
$fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY);
$fassert!(<$fty>::NEG_INFINITY.max(9.0), 9.0);
$fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0);
$fassert!(<$fty>::NEG_INFINITY.max(-9.0), -9.0);
$fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0);
$fassert!(<$fty>::NAN.max(9.0), 9.0);
$fassert!(<$fty>::NAN.max(-9.0), -9.0);
$fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0);
$fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0);
$fassert!(<$fty>::NAN.max(<$fty>::NAN).is_nan());
}
#[test]
fn minimum() {
@ -806,19 +806,19 @@ macro_rules! test_float {
$fassert!((-0.0 as $fty).minimum(9.0), -0.0);
$fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative());
$fassert!((-0.0 as $fty).minimum(-9.0), -9.0);
$fassert!(($inf as $fty).minimum(9.0), 9.0);
$fassert!((9.0 as $fty).minimum($inf), 9.0);
$fassert!(($inf as $fty).minimum(-9.0), -9.0);
$fassert!((-9.0 as $fty).minimum($inf), -9.0);
$fassert!(($neginf as $fty).minimum(9.0), $neginf);
$fassert!((9.0 as $fty).minimum($neginf), $neginf);
$fassert!(($neginf as $fty).minimum(-9.0), $neginf);
$fassert!((-9.0 as $fty).minimum($neginf), $neginf);
$fassert!(($nan as $fty).minimum(9.0).is_nan());
$fassert!(($nan as $fty).minimum(-9.0).is_nan());
$fassert!((9.0 as $fty).minimum($nan).is_nan());
$fassert!((-9.0 as $fty).minimum($nan).is_nan());
$fassert!(($nan as $fty).minimum($nan).is_nan());
$fassert!(<$fty>::INFINITY.minimum(9.0), 9.0);
$fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0);
$fassert!(<$fty>::INFINITY.minimum(-9.0), -9.0);
$fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0);
$fassert!(<$fty>::NEG_INFINITY.minimum(9.0), <$fty>::NEG_INFINITY);
$fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY);
$fassert!(<$fty>::NEG_INFINITY.minimum(-9.0), <$fty>::NEG_INFINITY);
$fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY);
$fassert!(<$fty>::NAN.minimum(9.0).is_nan());
$fassert!(<$fty>::NAN.minimum(-9.0).is_nan());
$fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan());
$fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan());
$fassert!(<$fty>::NAN.minimum(<$fty>::NAN).is_nan());
}
#[test]
fn maximum() {
@ -838,19 +838,19 @@ macro_rules! test_float {
$fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive());
$fassert!((-0.0 as $fty).maximum(-9.0), -0.0);
$fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative());
$fassert!(($inf as $fty).maximum(9.0), $inf);
$fassert!((9.0 as $fty).maximum($inf), $inf);
$fassert!(($inf as $fty).maximum(-9.0), $inf);
$fassert!((-9.0 as $fty).maximum($inf), $inf);
$fassert!(($neginf as $fty).maximum(9.0), 9.0);
$fassert!((9.0 as $fty).maximum($neginf), 9.0);
$fassert!(($neginf as $fty).maximum(-9.0), -9.0);
$fassert!((-9.0 as $fty).maximum($neginf), -9.0);
$fassert!(($nan as $fty).maximum(9.0).is_nan());
$fassert!(($nan as $fty).maximum(-9.0).is_nan());
$fassert!((9.0 as $fty).maximum($nan).is_nan());
$fassert!((-9.0 as $fty).maximum($nan).is_nan());
$fassert!(($nan as $fty).maximum($nan).is_nan());
$fassert!(<$fty>::INFINITY.maximum(9.0), <$fty>::INFINITY);
$fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY);
$fassert!(<$fty>::INFINITY.maximum(-9.0), <$fty>::INFINITY);
$fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY);
$fassert!(<$fty>::NEG_INFINITY.maximum(9.0), 9.0);
$fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0);
$fassert!(<$fty>::NEG_INFINITY.maximum(-9.0), -9.0);
$fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0);
$fassert!(<$fty>::NAN.maximum(9.0).is_nan());
$fassert!(<$fty>::NAN.maximum(-9.0).is_nan());
$fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan());
$fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan());
$fassert!(<$fty>::NAN.maximum(<$fty>::NAN).is_nan());
}
#[test]
fn midpoint() {
@ -863,38 +863,47 @@ macro_rules! test_float {
$fassert!((0.0 as $fty).midpoint(0.0), 0.0);
$fassert!((-0.0 as $fty).midpoint(-0.0), -0.0);
$fassert!((-5.0 as $fty).midpoint(5.0), 0.0);
$fassert!(($max as $fty).midpoint($min), 0.0);
$fassert!(($min as $fty).midpoint($max), -0.0);
$fassert!(($max as $fty).midpoint($min_pos), $max / 2.);
$fassert!((-$max as $fty).midpoint($min_pos), -$max / 2.);
$fassert!(($max as $fty).midpoint(-$min_pos), $max / 2.);
$fassert!((-$max as $fty).midpoint(-$min_pos), -$max / 2.);
$fassert!(($min_pos as $fty).midpoint($max), $max / 2.);
$fassert!(($min_pos as $fty).midpoint(-$max), -$max / 2.);
$fassert!((-$min_pos as $fty).midpoint($max), $max / 2.);
$fassert!((-$min_pos as $fty).midpoint(-$max), -$max / 2.);
$fassert!(($max as $fty).midpoint($max), $max);
$fassert!(($min_pos as $fty).midpoint($min_pos), $min_pos);
$fassert!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos);
$fassert!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5);
$fassert!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5);
$fassert!(($inf as $fty).midpoint($inf), $inf);
$fassert!(($neginf as $fty).midpoint($neginf), $neginf);
$fassert!(($nan as $fty).midpoint(1.0).is_nan());
$fassert!((1.0 as $fty).midpoint($nan).is_nan());
$fassert!(($nan as $fty).midpoint($nan).is_nan());
$fassert!(<$fty>::MAX.midpoint(<$fty>::MIN), 0.0);
$fassert!(<$fty>::MIN.midpoint(<$fty>::MAX), -0.0);
$fassert!(<$fty>::MAX.midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.);
$fassert!((-<$fty>::MAX).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.);
$fassert!(<$fty>::MAX.midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.);
$fassert!((-<$fty>::MAX).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.);
$fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.);
$fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.);
$fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.);
$fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.);
$fassert!(<$fty>::MAX.midpoint(<$fty>::MAX), <$fty>::MAX);
$fassert!(
(<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE),
<$fty>::MIN_POSITIVE
);
$fassert!(
(-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE),
-<$fty>::MIN_POSITIVE
);
$fassert!(<$fty>::MAX.midpoint(5.0), <$fty>::MAX / 2.0 + 2.5);
$fassert!(<$fty>::MAX.midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5);
$fassert!(<$fty>::INFINITY.midpoint(<$fty>::INFINITY), <$fty>::INFINITY);
$fassert!(
<$fty>::NEG_INFINITY.midpoint(<$fty>::NEG_INFINITY),
<$fty>::NEG_INFINITY
);
$fassert!(<$fty>::NAN.midpoint(1.0).is_nan());
$fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan());
$fassert!(<$fty>::NAN.midpoint(<$fty>::NAN).is_nan());
// test if large differences in magnitude are still correctly computed.
// NOTE: that because of how small x and y are, x + y can never overflow
// so (x + y) / 2.0 is always correct
// in particular, `2.pow(i)` will never be at the max exponent, so it could
// be safely doubled, while j is significantly smaller.
for i in $max_exp.saturating_sub(64)..$max_exp {
for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP {
for j in 0..64u8 {
let large = <$fty>::from(2.0f32).powi(i);
let large = (2.0 as $fty).powi(i);
// a much smaller number, such that there is no chance of overflow to test
// potential double rounding in midpoint's implementation.
let small = <$fty>::from(2.0f32).powi($max_exp - 1)
let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1)
* <$fty>::EPSILON
* <$fty>::from(j);
@ -906,23 +915,37 @@ macro_rules! test_float {
}
}
#[test]
fn abs() {
$fassert!((-1.0 as $fty).abs(), 1.0);
$fassert!((1.0 as $fty).abs(), 1.0);
$fassert!(<$fty>::NEG_INFINITY.abs(), <$fty>::INFINITY);
$fassert!(<$fty>::INFINITY.abs(), <$fty>::INFINITY);
}
#[test]
fn copysign() {
$fassert!((1.0 as $fty).copysign(-2.0), -1.0);
$fassert!((-1.0 as $fty).copysign(2.0), 1.0);
$fassert!(<$fty>::INFINITY.copysign(-0.0), <$fty>::NEG_INFINITY);
$fassert!(<$fty>::NEG_INFINITY.copysign(0.0), <$fty>::INFINITY);
}
#[test]
fn rem_euclid() {
// FIXME: Use $fassert when rem_euclid becomes const
assert!($inf.rem_euclid((42.0 as $fty)).is_nan());
assert_eq!((42.0 as $fty).rem_euclid($inf), (42.0 as $fty));
assert!((42.0 as $fty).rem_euclid($nan).is_nan());
assert!($inf.rem_euclid($inf).is_nan());
assert!($inf.rem_euclid($nan).is_nan());
assert!($nan.rem_euclid($inf).is_nan());
assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan());
assert_eq!((42.0 as $fty).rem_euclid(<$fty>::INFINITY), (42.0 as $fty));
assert!((42.0 as $fty).rem_euclid(<$fty>::NAN).is_nan());
assert!(<$fty>::INFINITY.rem_euclid(<$fty>::INFINITY).is_nan());
assert!(<$fty>::INFINITY.rem_euclid(<$fty>::NAN).is_nan());
assert!(<$fty>::NAN.rem_euclid(<$fty>::INFINITY).is_nan());
}
#[test]
fn div_euclid() {
// FIXME: Use $fassert when div_euclid becomes const
assert_eq!((42.0 as $fty).div_euclid($inf), 0.0);
assert!((42.0 as $fty).div_euclid($nan).is_nan());
assert!($inf.div_euclid($inf).is_nan());
assert!($inf.div_euclid($nan).is_nan());
assert!($nan.div_euclid($inf).is_nan());
assert_eq!((42.0 as $fty).div_euclid(<$fty>::INFINITY), 0.0);
assert!((42.0 as $fty).div_euclid(<$fty>::NAN).is_nan());
assert!(<$fty>::INFINITY.div_euclid(<$fty>::INFINITY).is_nan());
assert!(<$fty>::INFINITY.div_euclid(<$fty>::NAN).is_nan());
assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan());
}
}
};
@ -948,51 +971,7 @@ macro_rules! float_const_assert {
};
}
test_float!(
f32,
float_assert,
f32,
f32::INFINITY,
f32::NEG_INFINITY,
f32::NAN,
f32::MIN,
f32::MAX,
f32::MIN_POSITIVE,
f32::MAX_EXP
);
test_float!(
f32_const,
float_const_assert,
f32,
f32::INFINITY,
f32::NEG_INFINITY,
f32::NAN,
f32::MIN,
f32::MAX,
f32::MIN_POSITIVE,
f32::MAX_EXP
);
test_float!(
f64,
float_assert,
f64,
f64::INFINITY,
f64::NEG_INFINITY,
f64::NAN,
f64::MIN,
f64::MAX,
f64::MIN_POSITIVE,
f64::MAX_EXP
);
test_float!(
f64_const,
float_const_assert,
f64,
f64::INFINITY,
f64::NEG_INFINITY,
f64::NAN,
f64::MIN,
f64::MAX,
f64::MIN_POSITIVE,
f64::MAX_EXP
);
test_float!(f32, float_assert, f32);
test_float!(f32_const, float_const_assert, f32);
test_float!(f64, float_assert, f64);
test_float!(f64_const, float_const_assert, f64);

View file

@ -1782,8 +1782,30 @@ fn test_eq_windows_file_type() {
// Change the readonly attribute of one file.
let mut perms = file1.metadata().unwrap().permissions();
perms.set_readonly(true);
file1.set_permissions(perms).unwrap();
file1.set_permissions(perms.clone()).unwrap();
#[cfg(target_vendor = "win7")]
let _g = ReadonlyGuard { file: &file1, perms };
assert_eq!(file1.metadata().unwrap().file_type(), file2.metadata().unwrap().file_type());
// Reset the attribute before the `TmpDir`'s drop that removes the
// associated directory, which fails with a `PermissionDenied` error when
// running under Windows 7.
#[cfg(target_vendor = "win7")]
struct ReadonlyGuard<'f> {
file: &'f File,
perms: fs::Permissions,
}
#[cfg(target_vendor = "win7")]
impl<'f> Drop for ReadonlyGuard<'f> {
fn drop(&mut self) {
self.perms.set_readonly(false);
let res = self.file.set_permissions(self.perms.clone());
if !thread::panicking() {
res.unwrap();
}
}
}
}
/// Regression test for https://github.com/rust-lang/rust/issues/50619.

View file

@ -276,12 +276,12 @@
// tidy-alphabetical-start
// stabilization was reverted after it hit beta
#![cfg_attr(not(bootstrap), feature(autodiff))]
#![feature(alloc_error_handler)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
#![feature(asm_experimental_arch)]
#![feature(autodiff)]
#![feature(cfg_sanitizer_cfi)]
#![feature(cfg_target_thread_local)]
#![feature(cfi_encoding)]
@ -636,12 +636,15 @@ pub mod simd {
#[doc(inline)]
pub use crate::std_float::StdFloat;
}
#[unstable(feature = "autodiff", issue = "124509")]
#[cfg(not(bootstrap))]
/// This module provides support for automatic differentiation.
pub mod autodiff {
/// This macro handles automatic differentiation.
pub use core::autodiff::autodiff;
pub use core::autodiff::{autodiff_forward, autodiff_reverse};
}
#[stable(feature = "futures_api", since = "1.36.0")]
pub mod task {
//! Types and Traits for working with asynchronous tasks.

View file

@ -2746,15 +2746,30 @@ impl Path {
/// # Examples
///
/// ```
/// use std::path::{Path, PathBuf};
/// use std::path::Path;
///
/// let path = Path::new("foo.rs");
/// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
/// assert_eq!(path.with_extension("txt"), Path::new("foo.txt"));
/// assert_eq!(path.with_extension(""), Path::new("foo"));
/// ```
///
/// Handling multiple extensions:
///
/// ```
/// use std::path::Path;
///
/// let path = Path::new("foo.tar.gz");
/// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar"));
/// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz"));
/// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt"));
/// assert_eq!(path.with_extension("xz"), Path::new("foo.tar.xz"));
/// assert_eq!(path.with_extension("").with_extension("txt"), Path::new("foo.txt"));
/// ```
///
/// Adding an extension where one did not exist:
///
/// ```
/// use std::path::Path;
///
/// let path = Path::new("foo");
/// assert_eq!(path.with_extension("rs"), Path::new("foo.rs"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {

View file

@ -608,6 +608,17 @@ impl<T: ?Sized> Mutex<T> {
let data = self.data.get_mut();
poison::map_result(self.poison.borrow(), |()| data)
}
/// Returns a raw pointer to the underlying data.
///
/// The returned pointer is always non-null and properly aligned, but it is
/// the user's responsibility to ensure that any reads and writes through it
/// are properly synchronized to avoid data races, and that it is not read
/// or written through after the mutex is dropped.
#[unstable(feature = "mutex_data_ptr", issue = "140368")]
pub fn data_ptr(&self) -> *mut T {
self.data.get()
}
}
#[stable(feature = "mutex_from", since = "1.24.0")]

View file

@ -634,6 +634,17 @@ impl<T: ?Sized> RwLock<T> {
let data = self.data.get_mut();
poison::map_result(self.poison.borrow(), |()| data)
}
/// Returns a raw pointer to the underlying data.
///
/// The returned pointer is always non-null and properly aligned, but it is
/// the user's responsibility to ensure that any reads and writes through it
/// are properly synchronized to avoid data races, and that it is not read
/// or written through after the lock is dropped.
#[unstable(feature = "rwlock_data_ptr", issue = "140368")]
pub fn data_ptr(&self) -> *mut T {
self.data.get()
}
}
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -349,6 +349,17 @@ impl<T: ?Sized> ReentrantLock<T> {
}
}
/// Returns a raw pointer to the underlying data.
///
/// The returned pointer is always non-null and properly aligned, but it is
/// the user's responsibility to ensure that any reads through it are
/// properly synchronized to avoid data races, and that it is not read
/// through after the lock is dropped.
#[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")]
pub fn data_ptr(&self) -> *const T {
&raw const self.data
}
unsafe fn increment_lock_count(&self) -> Option<()> {
unsafe {
*self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?;

View file

@ -19,11 +19,15 @@ impl Mutex {
}
#[inline]
// Make this a diagnostic item for Miri's concurrency model checker.
#[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")]
pub fn try_lock(&self) -> bool {
self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_ok()
}
#[inline]
// Make this a diagnostic item for Miri's concurrency model checker.
#[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")]
pub fn lock(&self) {
if self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_err() {
self.lock_contended();
@ -80,6 +84,8 @@ impl Mutex {
}
#[inline]
// Make this a diagnostic item for Miri's concurrency model checker.
#[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")]
pub unsafe fn unlock(&self) {
if self.futex.swap(UNLOCKED, Release) == CONTENDED {
// We only wake up one thread. When that thread locks the mutex, it

View file

@ -6,7 +6,7 @@ use crate::sys::pal::sync as pal;
use crate::sys::sync::OnceBox;
pub struct Mutex {
pub pal: OnceBox<pal::Mutex>,
pub(in crate::sys::sync) pal: OnceBox<pal::Mutex>,
}
impl Mutex {
@ -28,6 +28,8 @@ impl Mutex {
}
#[inline]
// Make this a diagnostic item for Miri's concurrency model checker.
#[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")]
pub fn lock(&self) {
// SAFETY: we call `init` above, therefore reentrant locking is safe.
// In `drop` we ensure that the mutex is not destroyed while locked.
@ -35,6 +37,8 @@ impl Mutex {
}
#[inline]
// Make this a diagnostic item for Miri's concurrency model checker.
#[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")]
pub unsafe fn unlock(&self) {
// SAFETY: the mutex can only be locked if it is already initialized
// and we observed this initialization since we observed the locking.
@ -42,6 +46,8 @@ impl Mutex {
}
#[inline]
// Make this a diagnostic item for Miri's concurrency model checker.
#[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")]
pub fn try_lock(&self) -> bool {
// SAFETY: we call `init` above, therefore reentrant locking is safe.
// In `drop` we ensure that the mutex is not destroyed while locked.

View file

@ -1430,6 +1430,7 @@ impl Step for Libunwind {
cfg.flag("-funwind-tables");
cfg.flag("-fvisibility=hidden");
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
cfg.include(root.join("include"));
cfg.cargo_metadata(false);
cfg.out_dir(&out_dir);
@ -1447,12 +1448,10 @@ impl Step for Libunwind {
cfg.define("__NO_STRING_INLINES", None);
cfg.define("__NO_MATH_INLINES", None);
cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
cfg.define("NDEBUG", None);
}
if self.target.is_windows() {
cfg.define("_LIBUNWIND_HIDE_SYMBOLS", "1");
cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
}
}

View file

@ -1,4 +1,8 @@
use std::path::Path;
use super::Job;
use crate::jobs::{JobDatabase, load_job_db};
use crate::{DOCKER_DIRECTORY, JOBS_YML_PATH, utils};
#[test]
fn lookup_job_pattern() {
@ -62,3 +66,65 @@ fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) {
assert_eq!(jobs, expected);
}
/// Validate that CodeBuild jobs use Docker images from ghcr.io registry.
/// This is needed because otherwise from CodeBuild we get rate limited by Docker Hub.
fn validate_codebuild_image(job: &Job) -> anyhow::Result<()> {
let is_job_on_codebuild = job.codebuild.unwrap_or(false);
if !is_job_on_codebuild {
// Jobs in GitHub Actions don't get rate limited by Docker Hub.
return Ok(());
}
let image_name = job.image();
// we hardcode host-x86_64 here, because in codebuild we only run jobs for this architecture.
let dockerfile_path =
Path::new(DOCKER_DIRECTORY).join("host-x86_64").join(&image_name).join("Dockerfile");
if !dockerfile_path.exists() {
return Err(anyhow::anyhow!(
"Dockerfile not found for CodeBuild job '{}' at path: {}",
job.name,
dockerfile_path.display()
));
}
let dockerfile_content = utils::read_to_string(&dockerfile_path)?;
// Check if all FROM statement uses ghcr.io registry
let has_ghcr_from = dockerfile_content
.lines()
.filter(|line| line.trim_start().to_lowercase().starts_with("from "))
.all(|line| line.contains("ghcr.io"));
if !has_ghcr_from {
return Err(anyhow::anyhow!(
"CodeBuild job '{}' must use ghcr.io registry in its Dockerfile FROM statement. \
Dockerfile path: {dockerfile_path:?}",
job.name,
));
}
Ok(())
}
#[test]
fn validate_jobs() {
let db = {
let default_jobs_file = Path::new(JOBS_YML_PATH);
let db_str = utils::read_to_string(default_jobs_file).unwrap();
load_job_db(&db_str).expect("Failed to load job database")
};
let all_jobs =
db.pr_jobs.iter().chain(db.try_jobs.iter()).chain(db.auto_jobs.iter()).collect::<Vec<_>>();
let errors: Vec<anyhow::Error> =
all_jobs.into_iter().filter_map(|job| validate_codebuild_image(job).err()).collect();
if !errors.is_empty() {
let error_messages =
errors.into_iter().map(|e| format!("- {e}")).collect::<Vec<_>>().join("\n");
panic!("Job validation failed:\n{error_messages}");
}
}

View file

@ -27,7 +27,7 @@ use crate::test_dashboard::generate_test_dashboard;
use crate::utils::{load_env_var, output_details};
const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/..");
const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
pub const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
const JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../github-actions/jobs.yml");
struct GitHubContext {

View file

@ -0,0 +1,58 @@
FROM ubuntu:24.10
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bzip2 \
g++ \
make \
ninja-build \
file \
curl \
ca-certificates \
python3 \
git \
cmake \
sudo \
gdb \
llvm-19-tools \
llvm-19-dev \
libedit-dev \
libssl-dev \
pkg-config \
zlib1g-dev \
xz-utils \
nodejs \
mingw-w64 \
# libgccjit dependencies
flex \
libmpfr-dev \
libgmp-dev \
libmpc3 \
libmpc-dev \
&& rm -rf /var/lib/apt/lists/*
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
# We are disabling CI LLVM since this builder is intentionally using a host
# LLVM, rather than the typical src/llvm-project LLVM.
ENV NO_DOWNLOAD_CI_LLVM 1
ENV EXTERNAL_LLVM 1
# Using llvm-link-shared due to libffi issues -- see #34486
ENV RUST_CONFIGURE_ARGS \
--build=aarch64-unknown-linux-gnu \
--llvm-root=/usr/lib/llvm-19 \
--enable-llvm-link-shared \
--set rust.randomize-layout=true \
--set rust.thin-lto-import-instr-limit=10
COPY scripts/shared.sh /scripts/
ARG SCRIPT_ARG
COPY scripts/stage_2_test_set1.sh /tmp/
COPY scripts/stage_2_test_set2.sh /tmp/
ENV SCRIPT "/tmp/${SCRIPT_ARG}"

View file

@ -2,8 +2,8 @@
set -ex
# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
../x.py --stage 2 test --skip src/tools/tidy
# NOTE: intentionally uses `x`, and `x.ps1` to make sure they work on Linux.
# Make sure that `x.py` is tested elsewhere.
# Run the `mir-opt` tests again but this time for a 32-bit target.
# This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have

View file

@ -121,7 +121,17 @@ pr:
env:
ENABLE_GCC_CODEGEN: "1"
DOCKER_SCRIPT: x86_64-gnu-llvm.sh
<<: *job-linux-16c
<<: *job-linux-4c
- name: aarch64-gnu-llvm-19-1
env:
IMAGE: aarch64-gnu-llvm-19
DOCKER_SCRIPT: stage_2_test_set1.sh
<<: *job-aarch64-linux-8c
- name: aarch64-gnu-llvm-19-2
env:
IMAGE: aarch64-gnu-llvm-19
DOCKER_SCRIPT: stage_2_test_set2.sh
<<: *job-aarch64-linux
- name: x86_64-gnu-tools
<<: *job-linux-36c-codebuild
@ -132,7 +142,7 @@ try:
- name: dist-x86_64-linux
env:
CODEGEN_BACKENDS: llvm,cranelift
<<: *job-linux-16c
<<: *job-linux-36c-codebuild
# Main CI jobs that have to be green to merge a commit into master
# These jobs automatically inherit envs.auto, to avoid repeating
@ -228,7 +238,7 @@ auto:
- name: dist-x86_64-linux
env:
CODEGEN_BACKENDS: llvm,cranelift
<<: *job-linux-16c
<<: *job-linux-36c-codebuild
- name: dist-x86_64-linux-alt
env:
@ -459,7 +469,9 @@ auto:
- name: aarch64-apple
env:
SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin
SCRIPT: >
./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin &&
./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin src/tools/cargo
RUST_CONFIGURE_ARGS: >-
--enable-sanitizers
--enable-profiler

View file

@ -63,7 +63,7 @@ represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`).
[`mk_args`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.mk_args
[adtdefid]: ./ty_module/generic_arguments.md#adtdef-and-defid
[`Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Predicate.html
[`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TraitRef.html
[`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TraitRef.html
[`ty::TyKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/type.TyKind.html
[traits]: ./traits/resolution.md

View file

@ -1,18 +0,0 @@
# `repr128`
The tracking issue for this feature is: [#56071]
[#56071]: https://github.com/rust-lang/rust/issues/56071
------------------------
The `repr128` feature adds support for `#[repr(u128)]` on `enum`s.
```rust
#![feature(repr128)]
#[repr(u128)]
enum Foo {
Bar(u64),
}
```

View file

@ -22,6 +22,7 @@ use rustc_resolve::rustdoc::{
MalformedGenerics, has_primitive_or_keyword_docs, prepare_to_doc_link_resolution,
source_span_for_markdown_range, strip_generics_from_path,
};
use rustc_session::config::CrateType;
use rustc_session::lint::Lint;
use rustc_span::BytePos;
use rustc_span::hygiene::MacroKind;
@ -1169,7 +1170,6 @@ impl LinkCollector<'_, '_> {
#[allow(rustc::potential_query_instability)]
pub(crate) fn resolve_ambiguities(&mut self) {
let mut ambiguous_links = mem::take(&mut self.ambiguous_links);
for ((item_id, path_str), info_items) in ambiguous_links.iter_mut() {
for info in info_items {
info.resolved.retain(|(res, _)| match res {
@ -2227,15 +2227,35 @@ fn ambiguity_error(
emit_error: bool,
) -> bool {
let mut descrs = FxHashSet::default();
let kinds = candidates
// proc macro can exist in multiple namespaces at once, so we need to compare `DefIds`
// to remove the candidate in the fn namespace.
let mut possible_proc_macro_id = None;
let is_proc_macro_crate = cx.tcx.crate_types() == &[CrateType::ProcMacro];
let mut kinds = candidates
.iter()
.map(
|(res, def_id)| {
if let Some(def_id) = def_id { Res::from_def_id(cx.tcx, *def_id) } else { *res }
},
)
.filter(|res| descrs.insert(res.descr()))
.map(|(res, def_id)| {
let r =
if let Some(def_id) = def_id { Res::from_def_id(cx.tcx, *def_id) } else { *res };
if is_proc_macro_crate && let Res::Def(DefKind::Macro(_), id) = r {
possible_proc_macro_id = Some(id);
}
r
})
.collect::<Vec<_>>();
// In order to properly dedup proc macros, we have to do it in two passes:
// 1. Completing the full traversal to find the possible duplicate in the macro namespace,
// 2. Another full traversal to eliminate the candidate in the fn namespace.
//
// Thus, we have to do an iteration after collection is finished.
//
// As an optimization, we only deduplicate if we're in a proc-macro crate,
// and only if we already found something that looks like a proc macro.
if is_proc_macro_crate && let Some(macro_id) = possible_proc_macro_id {
kinds.retain(|res| !matches!(res, Res::Def(DefKind::Fn, fn_id) if macro_id == *fn_id));
}
kinds.retain(|res| descrs.insert(res.descr()));
if descrs.len() == 1 {
// There is no way for users to disambiguate at this point, so better return the first
// candidate and not show a warning.

View file

@ -51,7 +51,7 @@ declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MO
impl EarlyLintPass for FieldScopedVisibilityModifiers {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
let ItemKind::Struct(_, ref st, _) = item.kind else {
let ItemKind::Struct(_, _, ref st) = item.kind else {
return;
};
for field in st.fields() {

View file

@ -12,7 +12,6 @@ use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty;
use rustc_session::impl_lint_pass;
use rustc_span::Span;
use rustc_span::symbol::Ident;
@ -109,11 +108,11 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<Hir
}
let bound_ty = cx.typeck_results().node_type(pat.hir_id);
if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
if let Some(inner_ty) = bound_ty.peel_refs().builtin_index() {
// The values need to use the `ref` keyword if they can't be copied.
// This will need to be adjusted if the lint want to support mutable access in the future
let src_is_ref = bound_ty.is_ref() && by_ref == hir::ByRef::No;
let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
let needs_ref = !(src_is_ref || is_copy(cx, inner_ty));
let slice_info = slices
.entry(value_hir_id)

View file

@ -41,7 +41,7 @@ declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]);
impl EarlyLintPass for PartialPubFields {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
let ItemKind::Struct(_, ref st, _) = item.kind else {
let ItemKind::Struct(_, _, ref st) = item.kind else {
return;
};

View file

@ -66,7 +66,7 @@ impl LateLintPass<'_> for TupleArrayConversions {
}
fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
let (ty::Array(ty, _) | ty::Slice(ty)) = cx.typeck_results().expr_ty(expr).kind() else {
let Some(ty) = cx.typeck_results().expr_ty(expr).builtin_index() else {
unreachable!("`expr` must be an array or slice due to `ExprKind::Array`");
};
@ -85,7 +85,7 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &
ExprKind::Path(_) => Some(elements.iter().collect()),
_ => None,
})
&& all_bindings_are_for_conv(cx, &[*ty], expr, elements, &locals, ToType::Array)
&& all_bindings_are_for_conv(cx, &[ty], expr, elements, &locals, ToType::Array)
&& !is_from_proc_macro(cx, expr)
{
span_lint_and_help(

View file

@ -436,11 +436,11 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
&& over(lb, rb, eq_generic_bound)
&& both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
},
(Enum(li, le, lg), Enum(ri, re, rg)) => {
eq_id(*li, *ri) && over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg)
(Enum(li, lg, le), Enum(ri, rg, re)) => {
eq_id(*li, *ri) && eq_generics(lg, rg) && over(&le.variants, &re.variants, eq_variant)
},
(Struct(li, lv, lg), Struct(ri, rv, rg)) | (Union(li, lv, lg), Union(ri, rv, rg)) => {
eq_id(*li, *ri) && eq_variant_data(lv, rv) && eq_generics(lg, rg)
(Struct(li, lg, lv), Struct(ri, rg, rv)) | (Union(li, lg, lv), Union(ri, rg, rv)) => {
eq_id(*li, *ri) && eq_generics(lg, rg) && eq_variant_data(lv, rv)
},
(
Trait(box ast::Trait {

View file

@ -235,9 +235,7 @@ impl Constant<'_> {
_ => None,
},
(Self::Vec(l), Self::Vec(r)) => {
let (ty::Array(cmp_type, _) | ty::Slice(cmp_type)) = *cmp_type.kind() else {
return None;
};
let cmp_type = cmp_type.builtin_index()?;
iter::zip(l, r)
.map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
.find(|r| r.is_none_or(|o| o != Ordering::Equal))

View file

@ -1,5 +1,4 @@
#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
#![allow(incomplete_features)]
#![feature(proc_macro_hygiene, proc_macro_quote, box_patterns)]
#![allow(clippy::useless_conversion, clippy::uninlined_format_args)]
extern crate proc_macro;

View file

@ -1,5 +1,4 @@
#![feature(repr128, proc_macro_quote, proc_macro_span)]
#![allow(incomplete_features)]
#![feature(proc_macro_quote, proc_macro_span)]
#![allow(clippy::field_reassign_with_default)]
#![allow(clippy::eq_op)]
#![allow(clippy::literal_string_with_formatting_args)]

View file

@ -1,7 +1,5 @@
//@no-rustfix: only some diagnostics have suggestions
#![feature(repr128)]
#![allow(incomplete_features)]
#![warn(
clippy::cast_precision_loss,
clippy::cast_possible_truncation,

View file

@ -1,5 +1,5 @@
error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:25:5
--> tests/ui/cast.rs:23:5
|
LL | x0 as f32;
| ^^^^^^^^^
@ -8,37 +8,37 @@ LL | x0 as f32;
= help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:29:5
--> tests/ui/cast.rs:27:5
|
LL | x1 as f32;
| ^^^^^^^^^
error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
--> tests/ui/cast.rs:32:5
--> tests/ui/cast.rs:30:5
|
LL | x1 as f64;
| ^^^^^^^^^
error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:36:5
--> tests/ui/cast.rs:34:5
|
LL | x2 as f32;
| ^^^^^^^^^
error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
--> tests/ui/cast.rs:40:5
--> tests/ui/cast.rs:38:5
|
LL | x3 as f32;
| ^^^^^^^^^
error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
--> tests/ui/cast.rs:43:5
--> tests/ui/cast.rs:41:5
|
LL | x3 as f64;
| ^^^^^^^^^
error: casting `f32` to `i32` may truncate the value
--> tests/ui/cast.rs:47:5
--> tests/ui/cast.rs:45:5
|
LL | 1f32 as i32;
| ^^^^^^^^^^^
@ -48,7 +48,7 @@ LL | 1f32 as i32;
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
error: casting `f32` to `u32` may truncate the value
--> tests/ui/cast.rs:50:5
--> tests/ui/cast.rs:48:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
@ -56,7 +56,7 @@ LL | 1f32 as u32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:50:5
--> tests/ui/cast.rs:48:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
@ -65,7 +65,7 @@ LL | 1f32 as u32;
= help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
error: casting `f64` to `f32` may truncate the value
--> tests/ui/cast.rs:54:5
--> tests/ui/cast.rs:52:5
|
LL | 1f64 as f32;
| ^^^^^^^^^^^
@ -73,7 +73,7 @@ LL | 1f64 as f32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `i32` to `i8` may truncate the value
--> tests/ui/cast.rs:57:5
--> tests/ui/cast.rs:55:5
|
LL | 1i32 as i8;
| ^^^^^^^^^^
@ -86,7 +86,7 @@ LL + i8::try_from(1i32);
|
error: casting `i32` to `u8` may truncate the value
--> tests/ui/cast.rs:60:5
--> tests/ui/cast.rs:58:5
|
LL | 1i32 as u8;
| ^^^^^^^^^^
@ -99,7 +99,7 @@ LL + u8::try_from(1i32);
|
error: casting `f64` to `isize` may truncate the value
--> tests/ui/cast.rs:63:5
--> tests/ui/cast.rs:61:5
|
LL | 1f64 as isize;
| ^^^^^^^^^^^^^
@ -107,7 +107,7 @@ LL | 1f64 as isize;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `usize` may truncate the value
--> tests/ui/cast.rs:66:5
--> tests/ui/cast.rs:64:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
@ -115,13 +115,13 @@ LL | 1f64 as usize;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:66:5
--> tests/ui/cast.rs:64:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
error: casting `u32` to `u16` may truncate the value
--> tests/ui/cast.rs:70:5
--> tests/ui/cast.rs:68:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^^^^^^^^
@ -134,7 +134,7 @@ LL + u16::try_from(1f32 as u32);
|
error: casting `f32` to `u32` may truncate the value
--> tests/ui/cast.rs:70:5
--> tests/ui/cast.rs:68:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
@ -142,13 +142,13 @@ LL | 1f32 as u32 as u16;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:70:5
--> tests/ui/cast.rs:68:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
error: casting `i32` to `i8` may truncate the value
--> tests/ui/cast.rs:76:22
--> tests/ui/cast.rs:74:22
|
LL | let _x: i8 = 1i32 as _;
| ^^^^^^^^^
@ -161,7 +161,7 @@ LL + let _x: i8 = 1i32.try_into();
|
error: casting `f32` to `i32` may truncate the value
--> tests/ui/cast.rs:79:9
--> tests/ui/cast.rs:77:9
|
LL | 1f32 as i32;
| ^^^^^^^^^^^
@ -169,7 +169,7 @@ LL | 1f32 as i32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `i32` may truncate the value
--> tests/ui/cast.rs:82:9
--> tests/ui/cast.rs:80:9
|
LL | 1f64 as i32;
| ^^^^^^^^^^^
@ -177,7 +177,7 @@ LL | 1f64 as i32;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u8` may truncate the value
--> tests/ui/cast.rs:85:9
--> tests/ui/cast.rs:83:9
|
LL | 1f32 as u8;
| ^^^^^^^^^^
@ -185,13 +185,13 @@ LL | 1f32 as u8;
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u8` may lose the sign of the value
--> tests/ui/cast.rs:85:9
--> tests/ui/cast.rs:83:9
|
LL | 1f32 as u8;
| ^^^^^^^^^^
error: casting `u8` to `i8` may wrap around the value
--> tests/ui/cast.rs:90:5
--> tests/ui/cast.rs:88:5
|
LL | 1u8 as i8;
| ^^^^^^^^^
@ -200,31 +200,31 @@ LL | 1u8 as i8;
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
error: casting `u16` to `i16` may wrap around the value
--> tests/ui/cast.rs:93:5
--> tests/ui/cast.rs:91:5
|
LL | 1u16 as i16;
| ^^^^^^^^^^^
error: casting `u32` to `i32` may wrap around the value
--> tests/ui/cast.rs:96:5
--> tests/ui/cast.rs:94:5
|
LL | 1u32 as i32;
| ^^^^^^^^^^^
error: casting `u64` to `i64` may wrap around the value
--> tests/ui/cast.rs:99:5
--> tests/ui/cast.rs:97:5
|
LL | 1u64 as i64;
| ^^^^^^^^^^^
error: casting `usize` to `isize` may wrap around the value
--> tests/ui/cast.rs:102:5
--> tests/ui/cast.rs:100:5
|
LL | 1usize as isize;
| ^^^^^^^^^^^^^^^
error: casting `usize` to `i8` may truncate the value
--> tests/ui/cast.rs:106:5
--> tests/ui/cast.rs:104:5
|
LL | 1usize as i8;
| ^^^^^^^^^^^^
@ -237,7 +237,7 @@ LL + i8::try_from(1usize);
|
error: casting `usize` to `i16` may truncate the value
--> tests/ui/cast.rs:110:5
--> tests/ui/cast.rs:108:5
|
LL | 1usize as i16;
| ^^^^^^^^^^^^^
@ -250,7 +250,7 @@ LL + i16::try_from(1usize);
|
error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
--> tests/ui/cast.rs:110:5
--> tests/ui/cast.rs:108:5
|
LL | 1usize as i16;
| ^^^^^^^^^^^^^
@ -259,7 +259,7 @@ LL | 1usize as i16;
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
--> tests/ui/cast.rs:115:5
--> tests/ui/cast.rs:113:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
@ -272,19 +272,19 @@ LL + i32::try_from(1usize);
|
error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:115:5
--> tests/ui/cast.rs:113:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
--> tests/ui/cast.rs:120:5
--> tests/ui/cast.rs:118:5
|
LL | 1usize as i64;
| ^^^^^^^^^^^^^
error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
--> tests/ui/cast.rs:126:5
--> tests/ui/cast.rs:124:5
|
LL | 1u16 as isize;
| ^^^^^^^^^^^^^
@ -293,13 +293,13 @@ LL | 1u16 as isize;
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:130:5
--> tests/ui/cast.rs:128:5
|
LL | 1u32 as isize;
| ^^^^^^^^^^^^^
error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:134:5
--> tests/ui/cast.rs:132:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
@ -312,55 +312,55 @@ LL + isize::try_from(1u64);
|
error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
--> tests/ui/cast.rs:134:5
--> tests/ui/cast.rs:132:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:140:5
--> tests/ui/cast.rs:138:5
|
LL | -1i32 as u32;
| ^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:144:5
--> tests/ui/cast.rs:142:5
|
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
error: casting `i8` to `u8` may lose the sign of the value
--> tests/ui/cast.rs:156:5
--> tests/ui/cast.rs:154:5
|
LL | (i8::MIN).abs() as u8;
| ^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
--> tests/ui/cast.rs:161:5
--> tests/ui/cast.rs:159:5
|
LL | (-1i64).abs() as u64;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:163:5
--> tests/ui/cast.rs:161:5
|
LL | (-1isize).abs() as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
--> tests/ui/cast.rs:171:5
--> tests/ui/cast.rs:169:5
|
LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
--> tests/ui/cast.rs:187:5
--> tests/ui/cast.rs:185:5
|
LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `i8` may truncate the value
--> tests/ui/cast.rs:239:5
--> tests/ui/cast.rs:237:5
|
LL | (-99999999999i64).min(1) as i8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -373,7 +373,7 @@ LL + i8::try_from((-99999999999i64).min(1));
|
error: casting `u64` to `u8` may truncate the value
--> tests/ui/cast.rs:253:5
--> tests/ui/cast.rs:251:5
|
LL | 999999u64.clamp(0, 256) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -386,7 +386,7 @@ LL + u8::try_from(999999u64.clamp(0, 256));
|
error: casting `main::E2` to `u8` may truncate the value
--> tests/ui/cast.rs:276:21
--> tests/ui/cast.rs:274:21
|
LL | let _ = self as u8;
| ^^^^^^^^^^
@ -399,7 +399,7 @@ LL + let _ = u8::try_from(self);
|
error: casting `main::E2::B` to `u8` will truncate the value
--> tests/ui/cast.rs:279:21
--> tests/ui/cast.rs:277:21
|
LL | let _ = Self::B as u8;
| ^^^^^^^^^^^^^
@ -408,7 +408,7 @@ LL | let _ = Self::B as u8;
= help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
error: casting `main::E5` to `i8` may truncate the value
--> tests/ui/cast.rs:321:21
--> tests/ui/cast.rs:319:21
|
LL | let _ = self as i8;
| ^^^^^^^^^^
@ -421,13 +421,13 @@ LL + let _ = i8::try_from(self);
|
error: casting `main::E5::A` to `i8` will truncate the value
--> tests/ui/cast.rs:324:21
--> tests/ui/cast.rs:322:21
|
LL | let _ = Self::A as i8;
| ^^^^^^^^^^^^^
error: casting `main::E6` to `i16` may truncate the value
--> tests/ui/cast.rs:342:21
--> tests/ui/cast.rs:340:21
|
LL | let _ = self as i16;
| ^^^^^^^^^^^
@ -440,7 +440,7 @@ LL + let _ = i16::try_from(self);
|
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:362:21
--> tests/ui/cast.rs:360:21
|
LL | let _ = self as usize;
| ^^^^^^^^^^^^^
@ -453,7 +453,7 @@ LL + let _ = usize::try_from(self);
|
error: casting `main::E10` to `u16` may truncate the value
--> tests/ui/cast.rs:410:21
--> tests/ui/cast.rs:408:21
|
LL | let _ = self as u16;
| ^^^^^^^^^^^
@ -466,7 +466,7 @@ LL + let _ = u16::try_from(self);
|
error: casting `u32` to `u8` may truncate the value
--> tests/ui/cast.rs:422:13
--> tests/ui/cast.rs:420:13
|
LL | let c = (q >> 16) as u8;
| ^^^^^^^^^^^^^^^
@ -479,7 +479,7 @@ LL + let c = u8::try_from(q >> 16);
|
error: casting `u32` to `u8` may truncate the value
--> tests/ui/cast.rs:427:13
--> tests/ui/cast.rs:425:13
|
LL | let c = (q / 1000) as u8;
| ^^^^^^^^^^^^^^^^
@ -492,85 +492,85 @@ LL + let c = u8::try_from(q / 1000);
|
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:440:9
--> tests/ui/cast.rs:438:9
|
LL | (x * x) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:446:32
--> tests/ui/cast.rs:444:32
|
LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:449:5
--> tests/ui/cast.rs:447:5
|
LL | (2_i32).checked_pow(3).unwrap() as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:451:5
--> tests/ui/cast.rs:449:5
|
LL | (-2_i32).pow(3) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:456:5
--> tests/ui/cast.rs:454:5
|
LL | (-5_i32 % 2) as u32;
| ^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:459:5
--> tests/ui/cast.rs:457:5
|
LL | (-5_i32 % -2) as u32;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:463:5
--> tests/ui/cast.rs:461:5
|
LL | (-2_i32 >> 1) as u32;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:467:5
--> tests/ui/cast.rs:465:5
|
LL | (x * x) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:469:5
--> tests/ui/cast.rs:467:5
|
LL | (x * x * x) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:473:5
--> tests/ui/cast.rs:471:5
|
LL | (y * y * y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:476:5
--> tests/ui/cast.rs:474:5
|
LL | (y * y * y / y * 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:478:5
--> tests/ui/cast.rs:476:5
|
LL | (y * y / y * 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:481:5
--> tests/ui/cast.rs:479:5
|
LL | (y / y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `/`
--> tests/ui/cast.rs:481:6
--> tests/ui/cast.rs:479:6
|
LL | (y / y * y * -2) as u16;
| ^^^^^
@ -578,97 +578,97 @@ LL | (y / y * y * -2) as u16;
= note: `#[deny(clippy::eq_op)]` on by default
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:485:5
--> tests/ui/cast.rs:483:5
|
LL | (y + y + y + -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:488:5
--> tests/ui/cast.rs:486:5
|
LL | (y + y + y + 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:492:5
--> tests/ui/cast.rs:490:5
|
LL | (z + -2) as u16;
| ^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> tests/ui/cast.rs:495:5
--> tests/ui/cast.rs:493:5
|
LL | (z + z + 2) as u16;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:499:9
--> tests/ui/cast.rs:497:9
|
LL | (a * a * b * b * c * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:501:9
--> tests/ui/cast.rs:499:9
|
LL | (a * b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:504:9
--> tests/ui/cast.rs:502:9
|
LL | (a * -b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:507:9
--> tests/ui/cast.rs:505:9
|
LL | (a * b * c * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:509:9
--> tests/ui/cast.rs:507:9
|
LL | (a * -2) as u32;
| ^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:512:9
--> tests/ui/cast.rs:510:9
|
LL | (a * b * c * -2) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:515:9
--> tests/ui/cast.rs:513:9
|
LL | (a / b) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:517:9
--> tests/ui/cast.rs:515:9
|
LL | (a / b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:520:9
--> tests/ui/cast.rs:518:9
|
LL | (a / b + b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:523:9
--> tests/ui/cast.rs:521:9
|
LL | a.saturating_pow(3) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:526:9
--> tests/ui/cast.rs:524:9
|
LL | (a.abs() * b.pow(2) / c.abs()) as u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> tests/ui/cast.rs:534:21
--> tests/ui/cast.rs:532:21
|
LL | let _ = i32::MIN as u32; // cast_sign_loss
| ^^^^^^^^^^^^^^^
@ -679,7 +679,7 @@ LL | m!();
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: casting `u32` to `u8` may truncate the value
--> tests/ui/cast.rs:537:21
--> tests/ui/cast.rs:535:21
|
LL | let _ = u32::MAX as u8; // cast_possible_truncation
| ^^^^^^^^^^^^^^
@ -696,7 +696,7 @@ LL + let _ = u8::try_from(u32::MAX); // cast_possible_truncation
|
error: casting `f64` to `f32` may truncate the value
--> tests/ui/cast.rs:540:21
--> tests/ui/cast.rs:538:21
|
LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -708,7 +708,7 @@ LL | m!();
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
--> tests/ui/cast.rs:551:5
--> tests/ui/cast.rs:549:5
|
LL | bar.unwrap().unwrap() as usize
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -721,13 +721,13 @@ LL + usize::try_from(bar.unwrap().unwrap())
|
error: casting `i64` to `usize` may lose the sign of the value
--> tests/ui/cast.rs:551:5
--> tests/ui/cast.rs:549:5
|
LL | bar.unwrap().unwrap() as usize
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `u64` to `u8` may truncate the value
--> tests/ui/cast.rs:568:5
--> tests/ui/cast.rs:566:5
|
LL | (256 & 999999u64) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -740,7 +740,7 @@ LL + u8::try_from(256 & 999999u64);
|
error: casting `u64` to `u8` may truncate the value
--> tests/ui/cast.rs:571:5
--> tests/ui/cast.rs:569:5
|
LL | (255 % 999999u64) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,6 +1,3 @@
#![feature(repr128)]
#![allow(incomplete_features)]
extern crate proc_macro;
use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};

View file

@ -17,15 +17,6 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
@ -124,12 +115,9 @@ dependencies = [
[[package]]
name = "boxcar"
version = "0.2.11"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6740c6e2fc6360fa57c35214c7493826aee95993926092606f27c983b40837be"
dependencies = [
"loom",
]
checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf"
[[package]]
name = "camino"
@ -511,19 +499,6 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
[[package]]
name = "generator"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd"
dependencies = [
"cfg-if",
"libc",
"log",
"rustversion",
"windows 0.58.0",
]
[[package]]
name = "getrandom"
version = "0.2.15"
@ -1213,19 +1188,6 @@ version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]]
name = "loom"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
dependencies = [
"cfg-if",
"generator",
"scoped-tls",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "lsp-server"
version = "0.7.8"
@ -1265,15 +1227,6 @@ dependencies = [
"url",
]
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata 0.1.10",
]
[[package]]
name = "mbe"
version = "0.0.0"
@ -1400,16 +1353,6 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "nu-ansi-term"
version = "0.50.1"
@ -1471,12 +1414,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking_lot"
version = "0.12.3"
@ -1648,7 +1585,7 @@ dependencies = [
"indexmap",
"nix",
"tracing",
"windows 0.61.1",
"windows",
]
[[package]]
@ -1864,50 +1801,6 @@ dependencies = [
"thiserror 2.0.12",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.9",
"regex-syntax 0.8.5",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax 0.6.29",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.5",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rowan"
version = "0.15.15"
@ -2026,12 +1919,6 @@ dependencies = [
"smallvec",
]
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "ryu"
version = "1.0.20"
@ -2040,9 +1927,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "salsa"
version = "0.21.1"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f80d5cf3c3fcab2cef898012f242a670477a1baa609267376af9cb4409026c5"
checksum = "c8fff508e3d6ef42a32607f7538e17171a877a12015e32036f46e99d00c95781"
dependencies = [
"boxcar",
"crossbeam-queue",
@ -2063,15 +1950,15 @@ dependencies = [
[[package]]
name = "salsa-macro-rules"
version = "0.21.1"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05303d72606fbf2b9c9523cda2039bb8ecb00304027a3cd7e52b02a65c7d9185"
checksum = "8ea72b3c06f2ce6350fe3a0eeb7aaaf842d1d8352b706973c19c4f02e298a87c"
[[package]]
name = "salsa-macros"
version = "0.21.1"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb2f0e2a30c65cb3cd63440c491dde68d9af7e1be2b77832ac7057141107db50"
checksum = "0ce92025bc160b27814a207cb78d680973af17f863c7f4fc56cf3a535e22f378"
dependencies = [
"heck",
"proc-macro2",
@ -2556,15 +2443,9 @@ version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
dependencies = [
"matchers",
"nu-ansi-term 0.46.0",
"once_cell",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"time",
"tracing",
"tracing-core",
"tracing-log",
]
@ -2575,7 +2456,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c"
dependencies = [
"nu-ansi-term 0.50.1",
"nu-ansi-term",
"tracing-core",
"tracing-log",
"tracing-subscriber",
@ -2709,22 +2590,6 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.9"
@ -2734,22 +2599,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
dependencies = [
"windows-core 0.58.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.61.1"
@ -2757,7 +2606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
dependencies = [
"windows-collections",
"windows-core 0.61.0",
"windows-core",
"windows-future",
"windows-link",
"windows-numerics",
@ -2769,20 +2618,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-core 0.61.0",
]
[[package]]
name = "windows-core"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
"windows-implement 0.58.0",
"windows-interface 0.58.0",
"windows-result 0.2.0",
"windows-strings 0.1.0",
"windows-targets 0.52.6",
"windows-core",
]
[[package]]
@ -2791,11 +2627,11 @@ version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-implement",
"windows-interface",
"windows-link",
"windows-result 0.3.2",
"windows-strings 0.4.0",
"windows-result",
"windows-strings",
]
[[package]]
@ -2804,21 +2640,10 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
dependencies = [
"windows-core 0.61.0",
"windows-core",
"windows-link",
]
[[package]]
name = "windows-implement"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
@ -2830,17 +2655,6 @@ dependencies = [
"syn",
]
[[package]]
name = "windows-interface"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
@ -2864,19 +2678,10 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core 0.61.0",
"windows-core",
"windows-link",
]
[[package]]
name = "windows-result"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.3.2"
@ -2886,16 +2691,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
"windows-result 0.2.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-strings"
version = "0.4.0"

View file

@ -132,11 +132,8 @@ pulldown-cmark-to-cmark = "10.0.4"
pulldown-cmark = { version = "0.9.6", default-features = false }
rayon = "1.10.0"
rowan = "=0.15.15"
salsa = { version = "0.21.1", default-features = false, features = [
"rayon",
"salsa_unstable",
] }
salsa-macros = "0.21.1"
salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] }
salsa-macros = "0.22.0"
semver = "1.0.26"
serde = { version = "1.0.219" }
serde_derive = { version = "1.0.219" }

View file

@ -395,21 +395,21 @@ impl BuiltDependency {
pub type CratesIdMap = FxHashMap<CrateBuilderId, Crate>;
#[salsa_macros::input]
#[derive(Debug)]
#[derive(Debug, PartialOrd, Ord)]
pub struct Crate {
#[return_ref]
#[returns(ref)]
pub data: BuiltCrateData,
/// Crate data that is not needed for analysis.
///
/// This is split into a separate field to increase incrementality.
#[return_ref]
#[returns(ref)]
pub extra_data: ExtraCrateData,
// This is in `Arc` because it is shared for all crates in a workspace.
#[return_ref]
#[returns(ref)]
pub workspace_data: Arc<CrateWorkspaceData>,
#[return_ref]
#[returns(ref)]
pub cfg_options: CfgOptions,
#[return_ref]
#[returns(ref)]
pub env: Env,
}

View file

@ -32,6 +32,7 @@ pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet}
macro_rules! impl_intern_key {
($id:ident, $loc:ident) => {
#[salsa_macros::interned(no_lifetime)]
#[derive(PartialOrd, Ord)]
pub struct $id {
pub loc: $loc,
}
@ -165,6 +166,7 @@ impl Files {
}
#[salsa_macros::interned(no_lifetime, debug, constructor=from_span)]
#[derive(PartialOrd, Ord)]
pub struct EditionedFileId {
pub editioned_file_id: span::EditionedFileId,
}
@ -356,7 +358,7 @@ fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse<ast::SourceFil
}
fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<&[SyntaxError]> {
#[salsa_macros::tracked(return_ref)]
#[salsa_macros::tracked(returns(ref))]
fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<Box<[SyntaxError]>> {
let errors = db.parse(file_id).errors();
match &*errors {

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