Auto merge of #141696 - tgross35:rollup-fhpj180, r=tgross35
Rollup of 7 pull requests Successful merges: - rust-lang/rust#140369 (Add data_ptr method to Mutex and RwLock) - rust-lang/rust#140697 (Split `autodiff` into `autodiff_forward` and `autodiff_reverse`) - rust-lang/rust#141404 (Improve intrinsic handling in cg_ssa) - rust-lang/rust#141411 (rustdoc: linking to a local proc macro no longer warns) - rust-lang/rust#141548 (consider glob imports in cfg suggestion) - rust-lang/rust#141627 (Drop-build cleanups) - rust-lang/rust#141670 (Fix ICE in tokenstream with contracts from parser recovery) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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>>;
|
||||
|
||||
|
||||
@@ -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![] }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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, ..] => {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
#![feature(autodiff)]
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_forward;
|
||||
|
||||
#[autodiff(d_square3, Forward, Dual, DualOnly)]
|
||||
#[autodiff(d_square2, Forward, 4, Dual, DualOnly)]
|
||||
#[autodiff(d_square1, Forward, 4, Dual, Dual)]
|
||||
#[autodiff_forward(d_square3, Dual, DualOnly)]
|
||||
#[autodiff_forward(d_square2, 4, Dual, DualOnly)]
|
||||
#[autodiff_forward(d_square1, 4, Dual, Dual)]
|
||||
#[no_mangle]
|
||||
fn square(x: &f32) -> f32 {
|
||||
x * x
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
//@ needs-enzyme
|
||||
#![feature(autodiff)]
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
#[autodiff(d_square, Reverse, Duplicated, Active)]
|
||||
#[autodiff_reverse(d_square, Duplicated, Active)]
|
||||
fn square<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T {
|
||||
*x * *x
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
// identical function calls in the LLVM-IR, while having two different calls in the Rust code.
|
||||
#![feature(autodiff)]
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
#[autodiff(d_square, Reverse, Duplicated, Active)]
|
||||
#[autodiff_reverse(d_square, Duplicated, Active)]
|
||||
fn square(x: &f64) -> f64 {
|
||||
x * x
|
||||
}
|
||||
|
||||
#[autodiff(d_square2, Reverse, Duplicated, Active)]
|
||||
#[autodiff_reverse(d_square2, Duplicated, Active)]
|
||||
fn square2(x: &f64) -> f64 {
|
||||
x * x
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#![feature(autodiff)]
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
#[autodiff(d_square, Reverse, Duplicated, Active)]
|
||||
#[autodiff_reverse(d_square, Duplicated, Active)]
|
||||
fn square(x: &f64) -> f64 {
|
||||
x * x
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
//@ needs-enzyme
|
||||
#![feature(autodiff)]
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
#[autodiff(d_square, Reverse, Duplicated, Active)]
|
||||
#[autodiff_reverse(d_square, Duplicated, Active)]
|
||||
#[no_mangle]
|
||||
fn square(x: &f64) -> f64 {
|
||||
x * x
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
#![feature(autodiff)]
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
#[no_mangle]
|
||||
#[autodiff(df, Reverse, Active, Active, Active)]
|
||||
#[autodiff_reverse(df, Active, Active, Active)]
|
||||
fn primal(x: f32, y: f32) -> f64 {
|
||||
(x * x * y) as f64
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
//@ known-bug: #140683
|
||||
impl T {
|
||||
#[core::contracts::ensures]
|
||||
fn b() { (loop) }
|
||||
}
|
||||
@@ -13,7 +13,7 @@ extern crate std;
|
||||
|
||||
// Test that forward mode ad macros are expanded correctly.
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::{autodiff_forward, autodiff_reverse};
|
||||
|
||||
#[rustc_autodiff]
|
||||
#[inline(never)]
|
||||
|
||||
@@ -7,48 +7,48 @@
|
||||
|
||||
// Test that forward mode ad macros are expanded correctly.
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::{autodiff_forward, autodiff_reverse};
|
||||
|
||||
#[autodiff(df1, Forward, Dual, Const, Dual)]
|
||||
#[autodiff_forward(df1, Dual, Const, Dual)]
|
||||
pub fn f1(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[autodiff(df2, Forward, Dual, Const, Const)]
|
||||
#[autodiff_forward(df2, Dual, Const, Const)]
|
||||
pub fn f2(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[autodiff(df3, Forward, Dual, Const, Const)]
|
||||
#[autodiff_forward(df3, Dual, Const, Const)]
|
||||
pub fn f3(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Not the most interesting derivative, but who are we to judge
|
||||
#[autodiff(df4, Forward)]
|
||||
#[autodiff_forward(df4)]
|
||||
pub fn f4() {}
|
||||
|
||||
// We want to be sure that the same function can be differentiated in different ways
|
||||
#[autodiff(df5_rev, Reverse, Duplicated, Const, Active)]
|
||||
#[autodiff(df5_x, Forward, Dual, Const, Const)]
|
||||
#[autodiff(df5_y, Forward, Const, Dual, Const)]
|
||||
#[autodiff_reverse(df5_rev, Duplicated, Const, Active)]
|
||||
#[autodiff_forward(df5_x, Dual, Const, Const)]
|
||||
#[autodiff_forward(df5_y, Const, Dual, Const)]
|
||||
pub fn f5(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
struct DoesNotImplDefault;
|
||||
#[autodiff(df6, Forward, Const)]
|
||||
#[autodiff_forward(df6, Const)]
|
||||
pub fn f6() -> DoesNotImplDefault {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Make sure, that we add the None for the default return.
|
||||
#[autodiff(df7, Forward, Const)]
|
||||
#[autodiff_forward(df7, Const)]
|
||||
pub fn f7(x: f32) -> () {}
|
||||
|
||||
#[autodiff(f8_1, Forward, Dual, DualOnly)]
|
||||
#[autodiff(f8_2, Forward, 4, Dual, DualOnly)]
|
||||
#[autodiff(f8_3, Forward, 4, Dual, Dual)]
|
||||
#[autodiff_forward(f8_1, Dual, DualOnly)]
|
||||
#[autodiff_forward(f8_2, 4, Dual, DualOnly)]
|
||||
#[autodiff_forward(f8_3, 4, Dual, Dual)]
|
||||
#[no_mangle]
|
||||
fn f8(x: &f32) -> f32 {
|
||||
unimplemented!()
|
||||
@@ -56,15 +56,15 @@ fn f8(x: &f32) -> f32 {
|
||||
|
||||
// We want to make sure that we can use the macro for functions defined inside of functions
|
||||
pub fn f9() {
|
||||
#[autodiff(d_inner_1, Forward, Dual, DualOnly)]
|
||||
#[autodiff(d_inner_2, Forward, Dual, Dual)]
|
||||
#[autodiff_forward(d_inner_1, Dual, DualOnly)]
|
||||
#[autodiff_forward(d_inner_2, Dual, Dual)]
|
||||
fn inner(x: f32) -> f32 {
|
||||
x * x
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we can handle generics
|
||||
#[autodiff(d_square, Reverse, Duplicated, Active)]
|
||||
#[autodiff_reverse(d_square, Duplicated, Active)]
|
||||
pub fn f10<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T {
|
||||
*x * *x
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ extern crate std;
|
||||
|
||||
// Test that reverse mode ad macros are expanded correctly.
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
#[rustc_autodiff]
|
||||
#[inline(never)]
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
|
||||
// Test that reverse mode ad macros are expanded correctly.
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
#[autodiff(df1, Reverse, Duplicated, Const, Active)]
|
||||
#[autodiff_reverse(df1, Duplicated, Const, Active)]
|
||||
pub fn f1(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Not the most interesting derivative, but who are we to judge
|
||||
#[autodiff(df2, Reverse)]
|
||||
#[autodiff_reverse(df2)]
|
||||
pub fn f2() {}
|
||||
|
||||
#[autodiff(df3, Reverse, Duplicated, Const, Active)]
|
||||
#[autodiff_reverse(df3, Duplicated, Const, Active)]
|
||||
pub fn f3(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -27,12 +27,12 @@ enum Foo { Reverse }
|
||||
use Foo::Reverse;
|
||||
// What happens if we already have Reverse in type (enum variant decl) and value (enum variant
|
||||
// constructor) namespace? > It's expected to work normally.
|
||||
#[autodiff(df4, Reverse, Const)]
|
||||
#[autodiff_reverse(df4, Const)]
|
||||
pub fn f4(x: f32) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[autodiff(df5, Reverse, DuplicatedOnly, Duplicated)]
|
||||
#[autodiff_reverse(df5, DuplicatedOnly, Duplicated)]
|
||||
pub fn f5(x: *const f32, y: &f32) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ extern crate std;
|
||||
//@ pretty-compare-only
|
||||
//@ pp-exact:inherent_impl.pp
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
struct Foo {
|
||||
a: f64,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//@ pretty-compare-only
|
||||
//@ pp-exact:inherent_impl.pp
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
|
||||
struct Foo {
|
||||
a: f64,
|
||||
@@ -17,7 +17,7 @@ trait MyTrait {
|
||||
}
|
||||
|
||||
impl MyTrait for Foo {
|
||||
#[autodiff(df, Reverse, Const, Active, Active)]
|
||||
#[autodiff_reverse(df, Const, Active, Active)]
|
||||
fn f(&self, x: f64) -> f64 {
|
||||
self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln())
|
||||
}
|
||||
|
||||
21
tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.rs
Normal file
21
tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
//@ compile-flags: --crate-type=proc-macro --document-private-items
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
|
||||
//! Link to [`m`].
|
||||
//~^ ERROR `m` is both a module and a macro
|
||||
|
||||
// test a further edge case related to https://github.com/rust-lang/rust/issues/91274
|
||||
|
||||
// we need to make sure that when there is actually an ambiguity
|
||||
// in a proc-macro crate, we print out a sensible error.
|
||||
// because proc macro crates can't normally export modules,
|
||||
// this can only happen in --document-private-items mode.
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
mod m {}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn m(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
22
tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.stderr
Normal file
22
tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.stderr
Normal file
@@ -0,0 +1,22 @@
|
||||
error: `m` is both a module and a macro
|
||||
--> $DIR/bad-link-to-proc-macro.rs:4:15
|
||||
|
|
||||
LL | //! Link to [`m`].
|
||||
| ^ ambiguous link
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/bad-link-to-proc-macro.rs:2:9
|
||||
|
|
||||
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: to link to the module, prefix with `mod@`
|
||||
|
|
||||
LL | //! Link to [`mod@m`].
|
||||
| ++++
|
||||
help: to link to the macro, add an exclamation mark
|
||||
|
|
||||
LL | //! Link to [`m!`].
|
||||
| +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
13
tests/rustdoc/intra-doc/link-to-proc-macro.rs
Normal file
13
tests/rustdoc/intra-doc/link-to-proc-macro.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
//@ compile-flags: --crate-type=proc-macro
|
||||
//@ has 'foo/index.html' '//a[@href="macro.my_macro.html"]' 'my_macro'
|
||||
//! Link to [`my_macro`].
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// regression test for https://github.com/rust-lang/rust/issues/91274
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn my_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
@@ -7,38 +7,38 @@
|
||||
|
||||
// Test that invalid ad macros give nice errors and don't ICE.
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::{autodiff_forward, autodiff_reverse};
|
||||
|
||||
// We can't use Duplicated on scalars
|
||||
#[autodiff(df1, Reverse, Duplicated)]
|
||||
#[autodiff_reverse(df1, Duplicated)]
|
||||
pub fn f1(x: f64) {
|
||||
//~^ ERROR Duplicated can not be used for this type
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Too many activities
|
||||
#[autodiff(df3, Reverse, Duplicated, Const)]
|
||||
#[autodiff_reverse(df3, Duplicated, Const)]
|
||||
pub fn f3(x: f64) {
|
||||
//~^^ ERROR expected 1 activities, but found 2
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// To few activities
|
||||
#[autodiff(df4, Reverse)]
|
||||
#[autodiff_reverse(df4)]
|
||||
pub fn f4(x: f64) {
|
||||
//~^^ ERROR expected 1 activities, but found 0
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// We can't use Dual in Reverse mode
|
||||
#[autodiff(df5, Reverse, Dual)]
|
||||
#[autodiff_reverse(df5, Dual)]
|
||||
pub fn f5(x: f64) {
|
||||
//~^^ ERROR Dual can not be used in Reverse Mode
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// We can't use Duplicated in Forward mode
|
||||
#[autodiff(df6, Forward, Duplicated)]
|
||||
#[autodiff_forward(df6, Duplicated)]
|
||||
pub fn f6(x: f64) {
|
||||
//~^^ ERROR Duplicated can not be used in Forward Mode
|
||||
//~^^ ERROR Duplicated can not be used for this type
|
||||
@@ -46,36 +46,36 @@ pub fn f6(x: f64) {
|
||||
}
|
||||
|
||||
fn dummy() {
|
||||
#[autodiff(df7, Forward, Dual)]
|
||||
#[autodiff_forward(df7, Dual)]
|
||||
let mut x = 5;
|
||||
//~^ ERROR autodiff must be applied to function
|
||||
|
||||
#[autodiff(df7, Forward, Dual)]
|
||||
#[autodiff_forward(df7, Dual)]
|
||||
x = x + 3;
|
||||
//~^^ ERROR attributes on expressions are experimental [E0658]
|
||||
//~^^ ERROR autodiff must be applied to function
|
||||
|
||||
#[autodiff(df7, Forward, Dual)]
|
||||
#[autodiff_forward(df7, Dual)]
|
||||
let add_one_v2 = |x: u32| -> u32 { x + 1 };
|
||||
//~^ ERROR autodiff must be applied to function
|
||||
}
|
||||
|
||||
// Malformed, where args?
|
||||
#[autodiff]
|
||||
#[autodiff_forward]
|
||||
pub fn f7(x: f64) {
|
||||
//~^ ERROR autodiff requires at least a name and mode
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Malformed, where args?
|
||||
#[autodiff()]
|
||||
#[autodiff_forward()]
|
||||
pub fn f8(x: f64) {
|
||||
//~^ ERROR autodiff requires at least a name and mode
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Invalid attribute syntax
|
||||
#[autodiff = ""]
|
||||
#[autodiff_forward = ""]
|
||||
pub fn f9(x: f64) {
|
||||
//~^ ERROR autodiff requires at least a name and mode
|
||||
unimplemented!()
|
||||
@@ -84,29 +84,15 @@ pub fn f9(x: f64) {
|
||||
fn fn_exists() {}
|
||||
|
||||
// We colide with an already existing function
|
||||
#[autodiff(fn_exists, Reverse, Active)]
|
||||
#[autodiff_reverse(fn_exists, Active)]
|
||||
pub fn f10(x: f64) {
|
||||
//~^^ ERROR the name `fn_exists` is defined multiple times [E0428]
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Malformed, missing a mode
|
||||
#[autodiff(df11)]
|
||||
pub fn f11() {
|
||||
//~^ ERROR autodiff requires at least a name and mode
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Invalid Mode
|
||||
#[autodiff(df12, Debug)]
|
||||
pub fn f12() {
|
||||
//~^^ ERROR unknown Mode: `Debug`. Use `Forward` or `Reverse`
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Invalid, please pick one Mode
|
||||
// or use two autodiff macros.
|
||||
#[autodiff(df13, Forward, Reverse)]
|
||||
#[autodiff_reverse(df13, Reverse)]
|
||||
pub fn f13() {
|
||||
//~^^ ERROR did not recognize Activity: `Reverse`
|
||||
unimplemented!()
|
||||
@@ -117,7 +103,7 @@ struct Foo {}
|
||||
// We can't handle Active structs, because that would mean (in the general case), that we would
|
||||
// need to allocate and initialize arbitrary user types. We have Duplicated/Dual input args for
|
||||
// that. FIXME: Give a nicer error and suggest to the user to have a `&mut Foo` input instead.
|
||||
#[autodiff(df14, Reverse, Active, Active)]
|
||||
#[autodiff_reverse(df14, Active, Active)]
|
||||
fn f14(x: f32) -> Foo {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -127,14 +113,14 @@ type MyFloat = f32;
|
||||
// We would like to support type alias to f32/f64 in argument type in the future,
|
||||
// but that requires us to implement our checks at a later stage
|
||||
// like THIR which has type information available.
|
||||
#[autodiff(df15, Reverse, Active, Active)]
|
||||
#[autodiff_reverse(df15, Active, Active)]
|
||||
fn f15(x: MyFloat) -> f32 {
|
||||
//~^^ ERROR failed to resolve: use of undeclared type `MyFloat` [E0433]
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// We would like to support type alias to f32/f64 in return type in the future
|
||||
#[autodiff(df16, Reverse, Active, Active)]
|
||||
#[autodiff_reverse(df16, Active, Active)]
|
||||
fn f16(x: f32) -> MyFloat {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -145,40 +131,40 @@ struct F64Trans {
|
||||
}
|
||||
|
||||
// We would like to support `#[repr(transparent)]` f32/f64 wrapper in return type in the future
|
||||
#[autodiff(df17, Reverse, Active, Active)]
|
||||
#[autodiff_reverse(df17, Active, Active)]
|
||||
fn f17(x: f64) -> F64Trans {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// We would like to support `#[repr(transparent)]` f32/f64 wrapper in argument type in the future
|
||||
#[autodiff(df18, Reverse, Active, Active)]
|
||||
#[autodiff_reverse(df18, Active, Active)]
|
||||
fn f18(x: F64Trans) -> f64 {
|
||||
//~^^ ERROR failed to resolve: use of undeclared type `F64Trans` [E0433]
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Invalid return activity
|
||||
#[autodiff(df19, Forward, Dual, Active)]
|
||||
#[autodiff_forward(df19, Dual, Active)]
|
||||
fn f19(x: f32) -> f32 {
|
||||
//~^^ ERROR invalid return activity Active in Forward Mode
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[autodiff(df20, Reverse, Active, Dual)]
|
||||
#[autodiff_reverse(df20, Active, Dual)]
|
||||
fn f20(x: f32) -> f32 {
|
||||
//~^^ ERROR invalid return activity Dual in Reverse Mode
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Duplicated cannot be used as return activity
|
||||
#[autodiff(df21, Reverse, Active, Duplicated)]
|
||||
#[autodiff_reverse(df21, Active, Duplicated)]
|
||||
fn f21(x: f32) -> f32 {
|
||||
//~^^ ERROR invalid return activity Duplicated in Reverse Mode
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
struct DoesNotImplDefault;
|
||||
#[autodiff(df22, Forward, Dual)]
|
||||
#[autodiff_forward(df22, Dual)]
|
||||
pub fn f22() -> DoesNotImplDefault {
|
||||
//~^^ ERROR the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied
|
||||
unimplemented!()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0658]: attributes on expressions are experimental
|
||||
--> $DIR/autodiff_illegal.rs:53:5
|
||||
|
|
||||
LL | #[autodiff(df7, Forward, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_forward(df7, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
|
||||
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
|
||||
@@ -17,26 +17,26 @@ LL | pub fn f1(x: f64) {
|
||||
error: expected 1 activities, but found 2
|
||||
--> $DIR/autodiff_illegal.rs:20:1
|
||||
|
|
||||
LL | #[autodiff(df3, Reverse, Duplicated, Const)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_reverse(df3, Duplicated, Const)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: expected 1 activities, but found 0
|
||||
--> $DIR/autodiff_illegal.rs:27:1
|
||||
|
|
||||
LL | #[autodiff(df4, Reverse)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_reverse(df4)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Dual can not be used in Reverse Mode
|
||||
--> $DIR/autodiff_illegal.rs:34:1
|
||||
|
|
||||
LL | #[autodiff(df5, Reverse, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_reverse(df5, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Duplicated can not be used in Forward Mode
|
||||
--> $DIR/autodiff_illegal.rs:41:1
|
||||
|
|
||||
LL | #[autodiff(df6, Forward, Duplicated)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_forward(df6, Duplicated)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Duplicated can not be used for this type
|
||||
--> $DIR/autodiff_illegal.rs:42:14
|
||||
@@ -95,69 +95,54 @@ error[E0428]: the name `fn_exists` is defined multiple times
|
||||
LL | fn fn_exists() {}
|
||||
| -------------- previous definition of the value `fn_exists` here
|
||||
...
|
||||
LL | #[autodiff(fn_exists, Reverse, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn_exists` redefined here
|
||||
LL | #[autodiff_reverse(fn_exists, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn_exists` redefined here
|
||||
|
|
||||
= note: `fn_exists` must be defined only once in the value namespace of this module
|
||||
|
||||
error: autodiff requires at least a name and mode
|
||||
--> $DIR/autodiff_illegal.rs:95:1
|
||||
|
|
||||
LL | / pub fn f11() {
|
||||
LL | |
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: unknown Mode: `Debug`. Use `Forward` or `Reverse`
|
||||
--> $DIR/autodiff_illegal.rs:101:18
|
||||
|
|
||||
LL | #[autodiff(df12, Debug)]
|
||||
| ^^^^^
|
||||
|
||||
error: did not recognize Activity: `Reverse`
|
||||
--> $DIR/autodiff_illegal.rs:109:27
|
||||
--> $DIR/autodiff_illegal.rs:95:26
|
||||
|
|
||||
LL | #[autodiff(df13, Forward, Reverse)]
|
||||
| ^^^^^^^
|
||||
LL | #[autodiff_reverse(df13, Reverse)]
|
||||
| ^^^^^^^
|
||||
|
||||
error: invalid return activity Active in Forward Mode
|
||||
--> $DIR/autodiff_illegal.rs:161:1
|
||||
--> $DIR/autodiff_illegal.rs:147:1
|
||||
|
|
||||
LL | #[autodiff(df19, Forward, Dual, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_forward(df19, Dual, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid return activity Dual in Reverse Mode
|
||||
--> $DIR/autodiff_illegal.rs:167:1
|
||||
--> $DIR/autodiff_illegal.rs:153:1
|
||||
|
|
||||
LL | #[autodiff(df20, Reverse, Active, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_reverse(df20, Active, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid return activity Duplicated in Reverse Mode
|
||||
--> $DIR/autodiff_illegal.rs:174:1
|
||||
--> $DIR/autodiff_illegal.rs:160:1
|
||||
|
|
||||
LL | #[autodiff(df21, Reverse, Active, Duplicated)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_reverse(df21, Active, Duplicated)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0433]: failed to resolve: use of undeclared type `MyFloat`
|
||||
--> $DIR/autodiff_illegal.rs:130:1
|
||||
--> $DIR/autodiff_illegal.rs:116:1
|
||||
|
|
||||
LL | #[autodiff(df15, Reverse, Active, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat`
|
||||
LL | #[autodiff_reverse(df15, Active, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat`
|
||||
|
||||
error[E0433]: failed to resolve: use of undeclared type `F64Trans`
|
||||
--> $DIR/autodiff_illegal.rs:154:1
|
||||
--> $DIR/autodiff_illegal.rs:140:1
|
||||
|
|
||||
LL | #[autodiff(df18, Reverse, Active, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans`
|
||||
LL | #[autodiff_reverse(df18, Active, Active)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans`
|
||||
|
||||
error[E0599]: the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied
|
||||
--> $DIR/autodiff_illegal.rs:181:1
|
||||
--> $DIR/autodiff_illegal.rs:167:1
|
||||
|
|
||||
LL | struct DoesNotImplDefault;
|
||||
| ------------------------- doesn't satisfy `DoesNotImplDefault: Default`
|
||||
LL | #[autodiff(df22, Forward, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item cannot be called on `(DoesNotImplDefault, DoesNotImplDefault)` due to unsatisfied trait bounds
|
||||
LL | #[autodiff_forward(df22, Dual)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item cannot be called on `(DoesNotImplDefault, DoesNotImplDefault)` due to unsatisfied trait bounds
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`DoesNotImplDefault: Default`
|
||||
@@ -168,7 +153,7 @@ LL + #[derive(Default)]
|
||||
LL | struct DoesNotImplDefault;
|
||||
|
|
||||
|
||||
error: aborting due to 23 previous errors
|
||||
error: aborting due to 21 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0428, E0433, E0599, E0658.
|
||||
For more information about an error, try `rustc --explain E0428`.
|
||||
|
||||
@@ -3,6 +3,6 @@ use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
#[macro_use]
|
||||
pub fn autodiff(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pub fn autodiff_forward(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
item // identity proc-macro
|
||||
}
|
||||
|
||||
@@ -6,12 +6,11 @@
|
||||
#![feature(autodiff)]
|
||||
|
||||
#[cfg(std_autodiff)]
|
||||
use std::autodiff::autodiff;
|
||||
|
||||
use std::autodiff::autodiff_forward;
|
||||
extern crate my_macro;
|
||||
use my_macro::autodiff; // bring `autodiff` in scope
|
||||
use my_macro::autodiff_forward; // bring `autodiff_forward` in scope
|
||||
|
||||
#[autodiff]
|
||||
//[std_autodiff]~^^^ ERROR the name `autodiff` is defined multiple times
|
||||
#[autodiff_forward(dfoo)]
|
||||
//[std_autodiff]~^^^ ERROR the name `autodiff_forward` is defined multiple times
|
||||
//[std_autodiff]~^^ ERROR this rustc version does not support autodiff
|
||||
fn foo() {}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
error[E0252]: the name `autodiff` is defined multiple times
|
||||
--> $DIR/visibility.rs:12:5
|
||||
error[E0252]: the name `autodiff_forward` is defined multiple times
|
||||
--> $DIR/visibility.rs:11:5
|
||||
|
|
||||
LL | use std::autodiff::autodiff;
|
||||
| ----------------------- previous import of the macro `autodiff` here
|
||||
...
|
||||
LL | use my_macro::autodiff; // bring `autodiff` in scope
|
||||
| ^^^^^^^^^^^^^^^^^^ `autodiff` reimported here
|
||||
LL | use std::autodiff::autodiff_forward;
|
||||
| ------------------------------- previous import of the macro `autodiff_forward` here
|
||||
LL | extern crate my_macro;
|
||||
LL | use my_macro::autodiff_forward; // bring `autodiff_forward` in scope
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `autodiff_forward` reimported here
|
||||
|
|
||||
= note: `autodiff` must be defined only once in the macro namespace of this module
|
||||
= note: `autodiff_forward` must be defined only once in the macro namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use my_macro::autodiff as other_autodiff; // bring `autodiff` in scope
|
||||
| +++++++++++++++++
|
||||
LL | use my_macro::autodiff_forward as other_autodiff_forward; // bring `autodiff_forward` in scope
|
||||
| +++++++++++++++++++++++++
|
||||
|
||||
error: this rustc version does not support autodiff
|
||||
--> $DIR/visibility.rs:14:1
|
||||
--> $DIR/visibility.rs:13:1
|
||||
|
|
||||
LL | #[autodiff]
|
||||
| ^^^^^^^^^^^
|
||||
LL | #[autodiff_forward(dfoo)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
||||
61
tests/ui/cfg/diagnostics-reexport-2.rs
Normal file
61
tests/ui/cfg/diagnostics-reexport-2.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
// issue#141256
|
||||
|
||||
mod original {
|
||||
#[cfg(false)]
|
||||
//~^ NOTE the item is gated here
|
||||
//~| NOTE the item is gated here
|
||||
//~| NOTE the item is gated here
|
||||
//~| NOTE the item is gated here
|
||||
//~| NOTE the item is gated here
|
||||
pub mod gated {
|
||||
//~^ NOTE found an item that was configured out
|
||||
//~| NOTE found an item that was configured out
|
||||
//~| NOTE found an item that was configured out
|
||||
//~| NOTE found an item that was configured out
|
||||
//~| NOTE found an item that was configured out
|
||||
pub fn foo() {}
|
||||
}
|
||||
}
|
||||
|
||||
mod reexport {
|
||||
pub use super::original::*;
|
||||
}
|
||||
|
||||
mod reexport2 {
|
||||
pub use super::reexport::*;
|
||||
}
|
||||
|
||||
mod reexport30 {
|
||||
pub use super::original::*;
|
||||
pub use super::reexport31::*;
|
||||
}
|
||||
|
||||
mod reexport31 {
|
||||
pub use super::reexport30::*;
|
||||
}
|
||||
|
||||
mod reexport32 {
|
||||
pub use super::reexport30::*;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
reexport::gated::foo();
|
||||
//~^ ERROR failed to resolve: could not find `gated` in `reexport`
|
||||
//~| NOTE could not find `gated` in `reexport`
|
||||
|
||||
reexport2::gated::foo();
|
||||
//~^ ERROR failed to resolve: could not find `gated` in `reexport2`
|
||||
//~| NOTE could not find `gated` in `reexport2`
|
||||
|
||||
reexport30::gated::foo();
|
||||
//~^ ERROR failed to resolve: could not find `gated` in `reexport30`
|
||||
//~| NOTE could not find `gated` in `reexport30`
|
||||
|
||||
reexport31::gated::foo();
|
||||
//~^ ERROR failed to resolve: could not find `gated` in `reexport31`
|
||||
//~| NOTE could not find `gated` in `reexport31`
|
||||
|
||||
reexport32::gated::foo();
|
||||
//~^ ERROR failed to resolve: could not find `gated` in `reexport32`
|
||||
//~| NOTE could not find `gated` in `reexport32`
|
||||
}
|
||||
88
tests/ui/cfg/diagnostics-reexport-2.stderr
Normal file
88
tests/ui/cfg/diagnostics-reexport-2.stderr
Normal file
@@ -0,0 +1,88 @@
|
||||
error[E0433]: failed to resolve: could not find `gated` in `reexport`
|
||||
--> $DIR/diagnostics-reexport-2.rs:42:15
|
||||
|
|
||||
LL | reexport::gated::foo();
|
||||
| ^^^^^ could not find `gated` in `reexport`
|
||||
|
|
||||
note: found an item that was configured out
|
||||
--> $DIR/diagnostics-reexport-2.rs:10:13
|
||||
|
|
||||
LL | pub mod gated {
|
||||
| ^^^^^
|
||||
note: the item is gated here
|
||||
--> $DIR/diagnostics-reexport-2.rs:4:5
|
||||
|
|
||||
LL | #[cfg(false)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0433]: failed to resolve: could not find `gated` in `reexport2`
|
||||
--> $DIR/diagnostics-reexport-2.rs:46:16
|
||||
|
|
||||
LL | reexport2::gated::foo();
|
||||
| ^^^^^ could not find `gated` in `reexport2`
|
||||
|
|
||||
note: found an item that was configured out
|
||||
--> $DIR/diagnostics-reexport-2.rs:10:13
|
||||
|
|
||||
LL | pub mod gated {
|
||||
| ^^^^^
|
||||
note: the item is gated here
|
||||
--> $DIR/diagnostics-reexport-2.rs:4:5
|
||||
|
|
||||
LL | #[cfg(false)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0433]: failed to resolve: could not find `gated` in `reexport30`
|
||||
--> $DIR/diagnostics-reexport-2.rs:50:17
|
||||
|
|
||||
LL | reexport30::gated::foo();
|
||||
| ^^^^^ could not find `gated` in `reexport30`
|
||||
|
|
||||
note: found an item that was configured out
|
||||
--> $DIR/diagnostics-reexport-2.rs:10:13
|
||||
|
|
||||
LL | pub mod gated {
|
||||
| ^^^^^
|
||||
note: the item is gated here
|
||||
--> $DIR/diagnostics-reexport-2.rs:4:5
|
||||
|
|
||||
LL | #[cfg(false)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0433]: failed to resolve: could not find `gated` in `reexport31`
|
||||
--> $DIR/diagnostics-reexport-2.rs:54:17
|
||||
|
|
||||
LL | reexport31::gated::foo();
|
||||
| ^^^^^ could not find `gated` in `reexport31`
|
||||
|
|
||||
note: found an item that was configured out
|
||||
--> $DIR/diagnostics-reexport-2.rs:10:13
|
||||
|
|
||||
LL | pub mod gated {
|
||||
| ^^^^^
|
||||
note: the item is gated here
|
||||
--> $DIR/diagnostics-reexport-2.rs:4:5
|
||||
|
|
||||
LL | #[cfg(false)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0433]: failed to resolve: could not find `gated` in `reexport32`
|
||||
--> $DIR/diagnostics-reexport-2.rs:58:17
|
||||
|
|
||||
LL | reexport32::gated::foo();
|
||||
| ^^^^^ could not find `gated` in `reexport32`
|
||||
|
|
||||
note: found an item that was configured out
|
||||
--> $DIR/diagnostics-reexport-2.rs:10:13
|
||||
|
|
||||
LL | pub mod gated {
|
||||
| ^^^^^
|
||||
note: the item is gated here
|
||||
--> $DIR/diagnostics-reexport-2.rs:4:5
|
||||
|
|
||||
LL | #[cfg(false)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0658]: use of unstable library feature `autodiff`
|
||||
--> $DIR/feature-gate-autodiff-use.rs:13:3
|
||||
|
|
||||
LL | #[autodiff(dfoo, Reverse)]
|
||||
| ^^^^^^^^
|
||||
LL | #[autodiff_reverse(dfoo)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
|
||||
= help: add `#![feature(autodiff)]` to the crate attributes to enable
|
||||
@@ -11,8 +11,8 @@ LL | #[autodiff(dfoo, Reverse)]
|
||||
error[E0658]: use of unstable library feature `autodiff`
|
||||
--> $DIR/feature-gate-autodiff-use.rs:9:5
|
||||
|
|
||||
LL | use std::autodiff::autodiff;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | use std::autodiff::autodiff_reverse;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
|
||||
= help: add `#![feature(autodiff)]` to the crate attributes to enable
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0658]: use of unstable library feature `autodiff`
|
||||
--> $DIR/feature-gate-autodiff-use.rs:13:3
|
||||
|
|
||||
LL | #[autodiff(dfoo, Reverse)]
|
||||
| ^^^^^^^^
|
||||
LL | #[autodiff_reverse(dfoo)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
|
||||
= help: add `#![feature(autodiff)]` to the crate attributes to enable
|
||||
@@ -11,14 +11,14 @@ LL | #[autodiff(dfoo, Reverse)]
|
||||
error: this rustc version does not support autodiff
|
||||
--> $DIR/feature-gate-autodiff-use.rs:13:1
|
||||
|
|
||||
LL | #[autodiff(dfoo, Reverse)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[autodiff_reverse(dfoo)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0658]: use of unstable library feature `autodiff`
|
||||
--> $DIR/feature-gate-autodiff-use.rs:9:5
|
||||
|
|
||||
LL | use std::autodiff::autodiff;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | use std::autodiff::autodiff_reverse;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #124509 <https://github.com/rust-lang/rust/issues/124509> for more information
|
||||
= help: add `#![feature(autodiff)]` to the crate attributes to enable
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::autodiff::autodiff;
|
||||
use std::autodiff::autodiff_reverse;
|
||||
//[has_support]~^ ERROR use of unstable library feature `autodiff`
|
||||
//[no_support]~^^ ERROR use of unstable library feature `autodiff`
|
||||
|
||||
#[autodiff(dfoo, Reverse)]
|
||||
#[autodiff_reverse(dfoo)]
|
||||
//[has_support]~^ ERROR use of unstable library feature `autodiff` [E0658]
|
||||
//[no_support]~^^ ERROR use of unstable library feature `autodiff` [E0658]
|
||||
//[no_support]~| ERROR this rustc version does not support autodiff
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
error: cannot find attribute `autodiff` in this scope
|
||||
error: cannot find attribute `autodiff_reverse` in this scope
|
||||
--> $DIR/feature-gate-autodiff.rs:9:3
|
||||
|
|
||||
LL | #[autodiff(dfoo, Reverse)]
|
||||
| ^^^^^^^^
|
||||
LL | #[autodiff_reverse(dfoo)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider importing this attribute macro
|
||||
|
|
||||
LL + use std::autodiff::autodiff;
|
||||
LL + use std::autodiff::autodiff_reverse;
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
error: cannot find attribute `autodiff` in this scope
|
||||
error: cannot find attribute `autodiff_reverse` in this scope
|
||||
--> $DIR/feature-gate-autodiff.rs:9:3
|
||||
|
|
||||
LL | #[autodiff(dfoo, Reverse)]
|
||||
| ^^^^^^^^
|
||||
LL | #[autodiff_reverse(dfoo)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider importing this attribute macro
|
||||
|
|
||||
LL + use std::autodiff::autodiff;
|
||||
LL + use std::autodiff::autodiff_reverse;
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
// This checks that without the autodiff feature enabled, we can't use it.
|
||||
|
||||
#[autodiff(dfoo, Reverse)]
|
||||
//[has_support]~^ ERROR cannot find attribute `autodiff` in this scope
|
||||
//[no_support]~^^ ERROR cannot find attribute `autodiff` in this scope
|
||||
#[autodiff_reverse(dfoo)]
|
||||
//[has_support]~^ ERROR cannot find attribute `autodiff_reverse` in this scope
|
||||
//[no_support]~^^ ERROR cannot find attribute `autodiff_reverse` in this scope
|
||||
fn foo() {}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#![feature(contracts)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct T;
|
||||
|
||||
impl T {
|
||||
#[core::contracts::ensures] //~ ERROR expected a `Fn(&_)` closure, found `()`
|
||||
fn b() {(loop)}
|
||||
//~^ ERROR expected `{`, found `)`
|
||||
//~| ERROR expected `{`, found `)`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,34 @@
|
||||
error: expected `{`, found `)`
|
||||
--> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:8:18
|
||||
|
|
||||
LL | fn b() {(loop)}
|
||||
| ----^ expected `{`
|
||||
| |
|
||||
| while parsing this `loop` expression
|
||||
|
||||
error: expected `{`, found `)`
|
||||
--> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:8:18
|
||||
|
|
||||
LL | fn b() {(loop)}
|
||||
| ----^ expected `{`
|
||||
| |
|
||||
| while parsing this `loop` expression
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: expected a `Fn(&_)` closure, found `()`
|
||||
--> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:7:5
|
||||
|
|
||||
LL | #[core::contracts::ensures]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected an `Fn(&_)` closure, found `()`
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `for<'a> Fn(&'a _)` is not implemented for `()`
|
||||
note: required by a bound in `build_check_ensures`
|
||||
--> $SRC_DIR/core/src/contracts.rs:LL:COL
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
macro_rules! m {
|
||||
(static a : () = $e:expr) => {
|
||||
static a : () = $e;
|
||||
//~^ ERROR macro expansion ends with an incomplete expression: expected expression
|
||||
}
|
||||
static a: () = $e;
|
||||
};
|
||||
}
|
||||
|
||||
m! { static a : () = (if b) }
|
||||
|
||||
@@ -1,33 +1,27 @@
|
||||
error: expected `{`, found `)`
|
||||
--> $DIR/no-close-delim-issue-139248.rs:10:27
|
||||
--> $DIR/no-close-delim-issue-139248.rs:9:27
|
||||
|
|
||||
LL | m! { static a : () = (if b) }
|
||||
| ^ expected `{`
|
||||
|
|
||||
note: the `if` expression is missing a block after this condition
|
||||
--> $DIR/no-close-delim-issue-139248.rs:10:26
|
||||
--> $DIR/no-close-delim-issue-139248.rs:9:26
|
||||
|
|
||||
LL | m! { static a : () = (if b) }
|
||||
| ^
|
||||
|
||||
error: expected `{`, found `)`
|
||||
--> $DIR/no-close-delim-issue-139248.rs:10:27
|
||||
--> $DIR/no-close-delim-issue-139248.rs:9:27
|
||||
|
|
||||
LL | m! { static a : () = (if b) }
|
||||
| ^ expected `{`
|
||||
|
|
||||
note: the `if` expression is missing a block after this condition
|
||||
--> $DIR/no-close-delim-issue-139248.rs:10:26
|
||||
--> $DIR/no-close-delim-issue-139248.rs:9:26
|
||||
|
|
||||
LL | m! { static a : () = (if b) }
|
||||
| ^
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: macro expansion ends with an incomplete expression: expected expression
|
||||
--> $DIR/no-close-delim-issue-139248.rs:5:28
|
||||
|
|
||||
LL | static a : () = $e;
|
||||
| ^ expected expression
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
||||
Reference in New Issue
Block a user