| author | bors <bors@rust-lang.org> 2026-06-25 19:36:46 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-25 19:36:46 UTC |
| log | bd08c9e71874a81670fe3938dbf85148e42c2b96 |
| tree | f916957d1091f90bc7b6e6bdc8f64525a4b6b578 |
| parent | fa36a479e492137fdf473a891206da127f132910 |
| parent | 65153e05af7fa85d2c5b6eac78c9a54673327820 |
Rollup of 15 pull requests
Successful merges:
- rust-lang/rust#155535 (export symbols: support macos/windows(32/64))
- rust-lang/rust#158253 (codegen_ssa: multiply scalable vec size by `vscale`)
- rust-lang/rust#158308 (Fix bug when rustdoc "go to only result" setting is not working as expected")
- rust-lang/rust#158345 (Use `transmute_neo` in `assume_init`)
- rust-lang/rust#158369 (std: abort when `resume_unwind` is called inside the panic hook)
- rust-lang/rust#158374 (disallow tail calling extern "rust-call" functions)
- rust-lang/rust#158380 (Revert "rebuild LLVM when `bootstrap.toml` config changes")
- rust-lang/rust#154398 (Add test for async Send with PhantomData<*mut ()> + unsafe impl Send + dyn Trait)
- rust-lang/rust#157181 (autodiff: stop always needing an alloca)
- rust-lang/rust#158278 (autodiff - typtree cleanups)
- rust-lang/rust#158311 (doc(unstable-book): fix typo "earier" -> "earlier" in default-visibility flag)
- rust-lang/rust#158318 (Make normalization in a test case resilient to dist compilation)
- rust-lang/rust#158338 (Reorganize `tests/ui/issues` [14/N])
- rust-lang/rust#158343 (Include `Item::const_stability` info in rustdoc JSON.)
- rust-lang/rust#158390 (Fix: auto trait, const trait bound)71 files changed, 1313 insertions(+), 618 deletions(-)
compiler/rustc_abi/src/extern_abi.rs+7-1| ... | ... | @@ -343,10 +343,16 @@ impl ExternAbi { |
| 343 | 343 | // This ABI does not support calls at all (except via assembly). |
| 344 | 344 | false |
| 345 | 345 | } |
| 346 | Self::RustCall => { | |
| 347 | // Argument untupling requires additional support for tail calls to be possible, | |
| 348 | // see <https://github.com/rust-lang/rust/pull/158248>. There is no real uses of | |
| 349 | // tail calling `extern "rust-call"` functions | |
| 350 | false | |
| 351 | } | |
| 352 | ||
| 346 | 353 | Self::C { .. } |
| 347 | 354 | | Self::System { .. } |
| 348 | 355 | | Self::Rust |
| 349 | | Self::RustCall | |
| 350 | 356 | | Self::RustCold |
| 351 | 357 | | Self::RustInvalid |
| 352 | 358 | | Self::Unadjusted |
compiler/rustc_codegen_gcc/src/builder.rs+4| ... | ... | @@ -1459,6 +1459,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { |
| 1459 | 1459 | ); |
| 1460 | 1460 | } |
| 1461 | 1461 | |
| 1462 | fn vscale(&mut self, _: Self::Type) -> Self::Value { | |
| 1463 | unimplemented!("`rustc_codegen_gcc` doesn't support scalable vectors yet") | |
| 1464 | } | |
| 1465 | ||
| 1462 | 1466 | fn select( |
| 1463 | 1467 | &mut self, |
| 1464 | 1468 | cond: RValue<'gcc>, |
compiler/rustc_codegen_llvm/src/builder.rs+4| ... | ... | @@ -1226,6 +1226,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { |
| 1226 | 1226 | } |
| 1227 | 1227 | } |
| 1228 | 1228 | |
| 1229 | fn vscale(&mut self, ty: &'ll Type) -> &'ll Value { | |
| 1230 | unsafe { llvm::LLVMRustBuildVScale(self.llbuilder, ty) } | |
| 1231 | } | |
| 1232 | ||
| 1229 | 1233 | fn select( |
| 1230 | 1234 | &mut self, |
| 1231 | 1235 | cond: &'ll Value, |
compiler/rustc_codegen_llvm/src/builder/autodiff.rs+16-5| ... | ... | @@ -3,6 +3,9 @@ use std::ptr; |
| 3 | 3 | use rustc_ast::expand::autodiff_attrs::{DiffActivity, DiffMode}; |
| 4 | 4 | use rustc_ast::expand::typetree::FncTree; |
| 5 | 5 | use rustc_codegen_ssa::common::TypeKind; |
| 6 | use rustc_codegen_ssa::mir::IntrinsicResult; | |
| 7 | use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; | |
| 8 | use rustc_codegen_ssa::mir::place::PlaceValue; | |
| 6 | 9 | use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; |
| 7 | 10 | use rustc_data_structures::thin_vec::ThinVec; |
| 8 | 11 | use rustc_hir::attrs::RustcAutodiff; |
| ... | ... | @@ -11,7 +14,7 @@ use rustc_middle::{bug, ty}; |
| 11 | 14 | use rustc_target::callconv::PassMode; |
| 12 | 15 | use tracing::debug; |
| 13 | 16 | |
| 14 | use crate::builder::{Builder, PlaceRef, UNNAMED}; | |
| 17 | use crate::builder::{Builder, UNNAMED}; | |
| 15 | 18 | use crate::context::SimpleCx; |
| 16 | 19 | use crate::declare::declare_simple_fn; |
| 17 | 20 | use crate::llvm::{self, TRUE, Type, Value}; |
| ... | ... | @@ -296,9 +299,10 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( |
| 296 | 299 | ret_ty: &'ll Type, |
| 297 | 300 | fn_args: &[&'ll Value], |
| 298 | 301 | attrs: &RustcAutodiff, |
| 299 | dest: PlaceRef<'tcx, &'ll Value>, | |
| 302 | dest_layout: ty::layout::TyAndLayout<'tcx>, | |
| 303 | dest_place: Option<PlaceValue<&'ll Value>>, | |
| 300 | 304 | fnc_tree: FncTree, |
| 301 | ) { | |
| 305 | ) -> IntrinsicResult<'tcx, &'ll Value> { | |
| 302 | 306 | // We have to pick the name depending on whether we want forward or reverse mode autodiff. |
| 303 | 307 | let mut ad_name: String = match attrs.mode { |
| 304 | 308 | DiffMode::Forward => "__enzyme_fwddiff", |
| ... | ... | @@ -381,11 +385,18 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( |
| 381 | 385 | let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None); |
| 382 | 386 | |
| 383 | 387 | let fn_ret_ty = builder.cx.val_ty(call); |
| 384 | if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) { | |
| 388 | if fn_ret_ty == builder.cx.type_void() || fn_ret_ty == builder.cx.type_struct(&[], false) { | |
| 385 | 389 | // If we return void or an empty struct, then our caller (due to how we generated it) |
| 386 | 390 | // does not expect a return value. As such, we have no pointer (or place) into which |
| 387 | 391 | // we could store our value, and would store into an undef, which would cause UB. |
| 388 | 392 | // As such, we just ignore the return value in those cases. |
| 389 | builder.store_to_place(call, dest.val); | |
| 393 | IntrinsicResult::Operand(OperandValue::ZeroSized) | |
| 394 | } else if let Some(dest_place) = dest_place { | |
| 395 | builder.store_to_place(call, dest_place); | |
| 396 | IntrinsicResult::WroteIntoPlace | |
| 397 | } else { | |
| 398 | IntrinsicResult::Operand( | |
| 399 | OperandRef::from_immediate_or_packed_pair(builder, call, dest_layout).val, | |
| 400 | ) | |
| 390 | 401 | } |
| 391 | 402 | } |
compiler/rustc_codegen_llvm/src/context.rs+1-4| ... | ... | @@ -978,10 +978,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { |
| 978 | 978 | } |
| 979 | 979 | |
| 980 | 980 | fn intrinsic_call_expects_place_always(&self, name: Symbol) -> bool { |
| 981 | matches!( | |
| 982 | name, | |
| 983 | sym::autodiff | sym::volatile_load | sym::unaligned_volatile_load | sym::black_box | |
| 984 | ) | |
| 981 | matches!(name, sym::volatile_load | sym::unaligned_volatile_load | sym::black_box) | |
| 985 | 982 | } |
| 986 | 983 | } |
| 987 | 984 |
compiler/rustc_codegen_llvm/src/intrinsic.rs+11-13| ... | ... | @@ -43,6 +43,7 @@ use crate::errors::{ |
| 43 | 43 | AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch, |
| 44 | 44 | OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, |
| 45 | 45 | }; |
| 46 | use crate::intrinsic::ty::typetree::fnc_typetrees; | |
| 46 | 47 | use crate::llvm::{self, Type, Value}; |
| 47 | 48 | use crate::type_of::LayoutLlvmExt; |
| 48 | 49 | use crate::va_arg::emit_va_arg; |
| ... | ... | @@ -223,12 +224,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { |
| 223 | 224 | ) |
| 224 | 225 | } |
| 225 | 226 | sym::autodiff => { |
| 226 | let result = PlaceRef { | |
| 227 | val: result_place.unwrap(), | |
| 228 | layout: result_layout, | |
| 229 | }; | |
| 230 | codegen_autodiff(self, tcx, instance, args, result); | |
| 231 | return IntrinsicResult::WroteIntoPlace; | |
| 227 | return codegen_autodiff(self, tcx, instance, args, result_layout, result_place); | |
| 232 | 228 | } |
| 233 | 229 | sym::offload => { |
| 234 | 230 | if tcx.sess.opts.unstable_opts.offload.is_empty() { |
| ... | ... | @@ -1728,8 +1724,9 @@ fn codegen_autodiff<'ll, 'tcx>( |
| 1728 | 1724 | tcx: TyCtxt<'tcx>, |
| 1729 | 1725 | instance: ty::Instance<'tcx>, |
| 1730 | 1726 | args: &[OperandRef<'tcx, &'ll Value>], |
| 1731 | result: PlaceRef<'tcx, &'ll Value>, | |
| 1732 | ) { | |
| 1727 | result_layout: ty::layout::TyAndLayout<'tcx>, | |
| 1728 | result_place: Option<PlaceValue<&'ll Value>>, | |
| 1729 | ) -> IntrinsicResult<'tcx, &'ll Value> { | |
| 1733 | 1730 | if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) { |
| 1734 | 1731 | let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutEnable); |
| 1735 | 1732 | } |
| ... | ... | @@ -1769,9 +1766,9 @@ fn codegen_autodiff<'ll, 'tcx>( |
| 1769 | 1766 | diff_id, |
| 1770 | 1767 | diff_args |
| 1771 | 1768 | ), |
| 1772 | Err(_) => { | |
| 1769 | Err(err) => { | |
| 1773 | 1770 | // An error has already been emitted |
| 1774 | return; | |
| 1771 | return IntrinsicResult::Err(err); | |
| 1775 | 1772 | } |
| 1776 | 1773 | }; |
| 1777 | 1774 | |
| ... | ... | @@ -1791,7 +1788,7 @@ fn codegen_autodiff<'ll, 'tcx>( |
| 1791 | 1788 | &mut diff_attrs.input_activity, |
| 1792 | 1789 | ); |
| 1793 | 1790 | |
| 1794 | let fnc_tree = rustc_middle::ty::fnc_typetrees(tcx, source_fn_ptr_ty); | |
| 1791 | let fnc_tree = fnc_typetrees(tcx, source_fn_ptr_ty); | |
| 1795 | 1792 | |
| 1796 | 1793 | // Build body |
| 1797 | 1794 | generate_enzyme_call( |
| ... | ... | @@ -1802,9 +1799,10 @@ fn codegen_autodiff<'ll, 'tcx>( |
| 1802 | 1799 | llret_ty, |
| 1803 | 1800 | &val_arr, |
| 1804 | 1801 | &diff_attrs, |
| 1805 | result, | |
| 1802 | result_layout, | |
| 1803 | result_place, | |
| 1806 | 1804 | fnc_tree, |
| 1807 | ); | |
| 1805 | ) | |
| 1808 | 1806 | } |
| 1809 | 1807 | |
| 1810 | 1808 | // Generates the LLVM code to offload a Rust function to a target device (e.g., GPU). |
compiler/rustc_codegen_llvm/src/llvm/ffi.rs+2| ... | ... | @@ -2139,6 +2139,8 @@ unsafe extern "C" { |
| 2139 | 2139 | IsVolatile: bool, |
| 2140 | 2140 | ) -> &'a Value; |
| 2141 | 2141 | |
| 2142 | pub(crate) fn LLVMRustBuildVScale<'a>(B: &Builder<'a>, Ty: &'a Type) -> &'a Value; | |
| 2143 | ||
| 2142 | 2144 | pub(crate) fn LLVMRustTimeTraceProfilerInitialize(); |
| 2143 | 2145 | |
| 2144 | 2146 | pub(crate) fn LLVMRustTimeTraceProfilerFinishThread(); |
compiler/rustc_codegen_ssa/src/back/link.rs+76-5| ... | ... | @@ -47,7 +47,7 @@ use rustc_session::{Session, filesearch}; |
| 47 | 47 | use rustc_span::Symbol; |
| 48 | 48 | use rustc_target::spec::crt_objects::CrtObjects; |
| 49 | 49 | use rustc_target::spec::{ |
| 50 | BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents, | |
| 50 | Arch, BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents, | |
| 51 | 51 | LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, Os, RelocModel, |
| 52 | 52 | RelroLevel, SanitizerSet, SplitDebuginfo, |
| 53 | 53 | }; |
| ... | ... | @@ -2413,6 +2413,69 @@ fn add_rpath_args( |
| 2413 | 2413 | } |
| 2414 | 2414 | } |
| 2415 | 2415 | |
| 2416 | fn strip_numeric_suffix<'a>(base: &'a str, suffix: impl AsRef<str>, fallback: &'a str) -> &'a str { | |
| 2417 | if suffix.as_ref().parse::<u32>().is_ok() { base } else { fallback } | |
| 2418 | } | |
| 2419 | ||
| 2420 | fn undecorate_c_symbol<'a>( | |
| 2421 | name: &'a str, | |
| 2422 | sess: &Session, | |
| 2423 | kind: SymbolExportKind, | |
| 2424 | ) -> Option<&'a str> { | |
| 2425 | match sess.target.binary_format { | |
| 2426 | BinaryFormat::MachO => { | |
| 2427 | // Mach-O: strip the leading underscore that all external symbols have. | |
| 2428 | // The Darwin linker's export_symbols will add it back. | |
| 2429 | name.strip_prefix('_') | |
| 2430 | } | |
| 2431 | BinaryFormat::Coff => { | |
| 2432 | // MSVC C++ mangled names start with '?' and use a completely different | |
| 2433 | // decorating scheme that includes '@@' as structural delimiters. | |
| 2434 | // They must not be subjected to C calling-convention undecoration. | |
| 2435 | if name.starts_with('?') { | |
| 2436 | return Some(name); | |
| 2437 | } | |
| 2438 | Some(match sess.target.arch { | |
| 2439 | Arch::X86 => { | |
| 2440 | // COFF 32-bit: strip calling-convention decorations. | |
| 2441 | if let Some(rest) = name.strip_prefix('@') { | |
| 2442 | // fastcall: @foo@N -> foo | |
| 2443 | rest.rsplit_once('@') | |
| 2444 | .map(|(base, suffix)| strip_numeric_suffix(base, suffix, name)) | |
| 2445 | .unwrap_or(name) | |
| 2446 | } else if let Some(stripped) = name.strip_prefix('_') { | |
| 2447 | if let Some((base, suffix)) = stripped.rsplit_once('@') { | |
| 2448 | // stdcall: _foo@N -> foo | |
| 2449 | strip_numeric_suffix(base, suffix, stripped) | |
| 2450 | } else { | |
| 2451 | // cdecl: _foo -> foo | |
| 2452 | stripped | |
| 2453 | } | |
| 2454 | } else { | |
| 2455 | // vectorcall: foo@@N -> foo | |
| 2456 | name.rsplit_once("@@") | |
| 2457 | .map(|(base, suffix)| strip_numeric_suffix(base, suffix, name)) | |
| 2458 | .unwrap_or(name) | |
| 2459 | } | |
| 2460 | } | |
| 2461 | Arch::X86_64 => { | |
| 2462 | // COFF 64-bit: vectorcall mangling (foo@@N -> foo) also applies on x86_64. | |
| 2463 | name.rsplit_once("@@") | |
| 2464 | .map(|(base, suffix)| strip_numeric_suffix(base, suffix, name)) | |
| 2465 | .unwrap_or(name) | |
| 2466 | } | |
| 2467 | Arch::Arm64EC if kind == SymbolExportKind::Text => { | |
| 2468 | // Arm64EC: `#` prefix distinguishes ARM64EC text symbols from x64 thunks. | |
| 2469 | name.strip_prefix('#').unwrap_or(name) | |
| 2470 | } | |
| 2471 | _ => name, | |
| 2472 | }) | |
| 2473 | } | |
| 2474 | // ELF: no decoration | |
| 2475 | _ => Some(name), | |
| 2476 | } | |
| 2477 | } | |
| 2478 | ||
| 2416 | 2479 | fn add_c_staticlib_symbols( |
| 2417 | 2480 | sess: &Session, |
| 2418 | 2481 | lib: &NativeLib, |
| ... | ... | @@ -2454,7 +2517,14 @@ fn add_c_staticlib_symbols( |
| 2454 | 2517 | } |
| 2455 | 2518 | |
| 2456 | 2519 | for symbol in object.symbols() { |
| 2457 | if symbol.scope() != object::SymbolScope::Dynamic { | |
| 2520 | // The `object` crate returns `Dynamic` for ELF/Mach-O global symbols, | |
| 2521 | // but always returns `Linkage` for COFF external symbols. | |
| 2522 | // Accept both for COFF (Windows and UEFI). | |
| 2523 | let scope = symbol.scope(); | |
| 2524 | if scope != object::SymbolScope::Dynamic | |
| 2525 | && !(sess.target.binary_format == BinaryFormat::Coff | |
| 2526 | && scope == object::SymbolScope::Linkage) | |
| 2527 | { | |
| 2458 | 2528 | continue; |
| 2459 | 2529 | } |
| 2460 | 2530 | |
| ... | ... | @@ -2469,9 +2539,10 @@ fn add_c_staticlib_symbols( |
| 2469 | 2539 | _ => continue, |
| 2470 | 2540 | }; |
| 2471 | 2541 | |
| 2472 | // FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple. | |
| 2473 | // Need to be resolved. | |
| 2474 | out.push((name.to_string(), export_kind)); | |
| 2542 | let Some(undecorated) = undecorate_c_symbol(name, sess, export_kind) else { | |
| 2543 | continue; | |
| 2544 | }; | |
| 2545 | out.push((undecorated.to_string(), export_kind)); | |
| 2475 | 2546 | } |
| 2476 | 2547 | } |
| 2477 | 2548 |
compiler/rustc_codegen_ssa/src/traits/builder.rs+11| ... | ... | @@ -476,6 +476,11 @@ pub trait BuilderMethods<'a, 'tcx>: |
| 476 | 476 | flags: MemFlags, |
| 477 | 477 | ); |
| 478 | 478 | |
| 479 | // Produce a value from calling the `vscale` intrinsic (containing the `vscale` multiplier that | |
| 480 | // a scalable vector's element size and count can be multiplied by to get the real size of the | |
| 481 | // vector) | |
| 482 | fn vscale(&mut self, ty: Self::Type) -> Self::Value; | |
| 483 | ||
| 479 | 484 | /// *Typed* copy for non-overlapping places. |
| 480 | 485 | /// |
| 481 | 486 | /// Has a default implementation in terms of `memcpy`, but specific backends |
| ... | ... | @@ -513,6 +518,12 @@ pub trait BuilderMethods<'a, 'tcx>: |
| 513 | 518 | temp.val.store_with_flags(self, dst.with_type(layout), flags); |
| 514 | 519 | } else if !layout.is_zst() { |
| 515 | 520 | let bytes = self.const_usize(layout.size.bytes()); |
| 521 | let bytes = if layout.peel_transparent_wrappers(self).ty.is_scalable_vector() { | |
| 522 | let vscale = self.vscale(self.type_i64()); | |
| 523 | self.mul(vscale, bytes) | |
| 524 | } else { | |
| 525 | bytes | |
| 526 | }; | |
| 516 | 527 | self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, None); |
| 517 | 528 | } |
| 518 | 529 | } |
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp+4| ... | ... | @@ -1497,6 +1497,10 @@ LLVMRustBuildMemMove(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, |
| 1497 | 1497 | unwrap(Size), IsVolatile)); |
| 1498 | 1498 | } |
| 1499 | 1499 | |
| 1500 | extern "C" LLVMValueRef LLVMRustBuildVScale(LLVMBuilderRef B, LLVMTypeRef Ty) { | |
| 1501 | return wrap(unwrap(B)->CreateVScale(unwrap(Ty))); | |
| 1502 | } | |
| 1503 | ||
| 1500 | 1504 | extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst, |
| 1501 | 1505 | unsigned DstAlign, LLVMValueRef Val, |
| 1502 | 1506 | LLVMValueRef Size, |
compiler/rustc_middle/src/ty/mod.rs+2-227| ... | ... | @@ -27,7 +27,6 @@ pub use intrinsic::IntrinsicDef; |
| 27 | 27 | use rustc_abi::{ |
| 28 | 28 | Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx, |
| 29 | 29 | }; |
| 30 | use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; | |
| 31 | 30 | use rustc_ast::node_id::NodeMap; |
| 32 | 31 | use rustc_ast::{self as ast}; |
| 33 | 32 | pub use rustc_ast_ir::{Movability, Mutability, try_visit}; |
| ... | ... | @@ -67,7 +66,7 @@ pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleF |
| 67 | 66 | pub use rustc_type_ir::*; |
| 68 | 67 | #[allow(hidden_glob_reexports, unused_imports)] |
| 69 | 68 | use rustc_type_ir::{InferCtxtLike, Interner}; |
| 70 | use tracing::{debug, instrument, trace}; | |
| 69 | use tracing::{debug, instrument}; | |
| 71 | 70 | pub use vtable::*; |
| 72 | 71 | |
| 73 | 72 | pub use self::closure::{ |
| ... | ... | @@ -144,6 +143,7 @@ pub mod print; |
| 144 | 143 | pub mod relate; |
| 145 | 144 | pub mod significant_drop_order; |
| 146 | 145 | pub mod trait_def; |
| 146 | pub mod typetree; | |
| 147 | 147 | pub mod util; |
| 148 | 148 | pub mod vtable; |
| 149 | 149 | |
| ... | ... | @@ -2390,228 +2390,3 @@ pub struct DestructuredAdtConst<'tcx> { |
| 2390 | 2390 | pub variant: VariantIdx, |
| 2391 | 2391 | pub fields: &'tcx [ty::Const<'tcx>], |
| 2392 | 2392 | } |
| 2393 | ||
| 2394 | /// Generate TypeTree information for autodiff. | |
| 2395 | /// This function creates TypeTree metadata that describes the memory layout | |
| 2396 | /// of function parameters and return types for Enzyme autodiff. | |
| 2397 | pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree { | |
| 2398 | // Check if TypeTrees are disabled via NoTT flag | |
| 2399 | if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) { | |
| 2400 | return FncTree { args: vec![], ret: TypeTree::new() }; | |
| 2401 | } | |
| 2402 | ||
| 2403 | // Check if this is actually a function type | |
| 2404 | if !fn_ty.is_fn() { | |
| 2405 | return FncTree { args: vec![], ret: TypeTree::new() }; | |
| 2406 | } | |
| 2407 | ||
| 2408 | // Get the function signature | |
| 2409 | let fn_sig = fn_ty.fn_sig(tcx); | |
| 2410 | let sig = tcx.instantiate_bound_regions_with_erased(fn_sig); | |
| 2411 | ||
| 2412 | // Create TypeTrees for each input parameter | |
| 2413 | let mut args = vec![]; | |
| 2414 | for ty in sig.inputs().iter() { | |
| 2415 | let type_tree = typetree_from_ty(tcx, *ty); | |
| 2416 | args.push(type_tree); | |
| 2417 | } | |
| 2418 | ||
| 2419 | // Create TypeTree for return type | |
| 2420 | let ret = typetree_from_ty(tcx, sig.output()); | |
| 2421 | ||
| 2422 | FncTree { args, ret } | |
| 2423 | } | |
| 2424 | ||
| 2425 | /// Generate TypeTree for a specific type. | |
| 2426 | /// This function analyzes a Rust type and creates appropriate TypeTree metadata. | |
| 2427 | pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { | |
| 2428 | let mut visited = Vec::new(); | |
| 2429 | typetree_from_ty_inner(tcx, ty, 0, &mut visited) | |
| 2430 | } | |
| 2431 | ||
| 2432 | /// Maximum recursion depth for TypeTree generation to prevent stack overflow | |
| 2433 | /// from pathological deeply nested types. Combined with cycle detection. | |
| 2434 | const MAX_TYPETREE_DEPTH: usize = 6; | |
| 2435 | ||
| 2436 | /// Internal recursive function for TypeTree generation with cycle detection and depth limiting. | |
| 2437 | fn typetree_from_ty_inner<'tcx>( | |
| 2438 | tcx: TyCtxt<'tcx>, | |
| 2439 | ty: Ty<'tcx>, | |
| 2440 | depth: usize, | |
| 2441 | visited: &mut Vec<Ty<'tcx>>, | |
| 2442 | ) -> TypeTree { | |
| 2443 | if depth >= MAX_TYPETREE_DEPTH { | |
| 2444 | trace!("typetree depth limit {} reached for type: {}", MAX_TYPETREE_DEPTH, ty); | |
| 2445 | return TypeTree::new(); | |
| 2446 | } | |
| 2447 | ||
| 2448 | if visited.contains(&ty) { | |
| 2449 | return TypeTree::new(); | |
| 2450 | } | |
| 2451 | ||
| 2452 | visited.push(ty); | |
| 2453 | let result = typetree_from_ty_impl(tcx, ty, depth, visited); | |
| 2454 | visited.pop(); | |
| 2455 | result | |
| 2456 | } | |
| 2457 | ||
| 2458 | /// Implementation of TypeTree generation logic. | |
| 2459 | fn typetree_from_ty_impl<'tcx>( | |
| 2460 | tcx: TyCtxt<'tcx>, | |
| 2461 | ty: Ty<'tcx>, | |
| 2462 | depth: usize, | |
| 2463 | visited: &mut Vec<Ty<'tcx>>, | |
| 2464 | ) -> TypeTree { | |
| 2465 | typetree_from_ty_impl_inner(tcx, ty, depth, visited, false) | |
| 2466 | } | |
| 2467 | ||
| 2468 | /// Internal implementation with context about whether this is for a reference target. | |
| 2469 | fn typetree_from_ty_impl_inner<'tcx>( | |
| 2470 | tcx: TyCtxt<'tcx>, | |
| 2471 | ty: Ty<'tcx>, | |
| 2472 | depth: usize, | |
| 2473 | visited: &mut Vec<Ty<'tcx>>, | |
| 2474 | is_reference_target: bool, | |
| 2475 | ) -> TypeTree { | |
| 2476 | if ty.is_scalar() { | |
| 2477 | let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { | |
| 2478 | (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) | |
| 2479 | } else if ty.is_floating_point() { | |
| 2480 | match ty { | |
| 2481 | x if x == tcx.types.f16 => (Kind::Half, 2), | |
| 2482 | x if x == tcx.types.f32 => (Kind::Float, 4), | |
| 2483 | x if x == tcx.types.f64 => (Kind::Double, 8), | |
| 2484 | x if x == tcx.types.f128 => (Kind::F128, 16), | |
| 2485 | _ => (Kind::Integer, 0), | |
| 2486 | } | |
| 2487 | } else { | |
| 2488 | (Kind::Integer, 0) | |
| 2489 | }; | |
| 2490 | ||
| 2491 | // Use offset 0 for scalars that are direct targets of references (like &f64) | |
| 2492 | // Use offset -1 for scalars used directly (like function return types) | |
| 2493 | let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 }; | |
| 2494 | return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]); | |
| 2495 | } | |
| 2496 | ||
| 2497 | if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { | |
| 2498 | let Some(inner_ty) = ty.builtin_deref(true) else { | |
| 2499 | return TypeTree::new(); | |
| 2500 | }; | |
| 2501 | ||
| 2502 | let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true); | |
| 2503 | return TypeTree(vec![Type { | |
| 2504 | offset: -1, | |
| 2505 | size: tcx.data_layout.pointer_size().bytes_usize(), | |
| 2506 | kind: Kind::Pointer, | |
| 2507 | child, | |
| 2508 | }]); | |
| 2509 | } | |
| 2510 | ||
| 2511 | if ty.is_array() { | |
| 2512 | if let ty::Array(element_ty, len_const) = ty.kind() { | |
| 2513 | let len = len_const.try_to_target_usize(tcx).unwrap_or(0); | |
| 2514 | if len == 0 { | |
| 2515 | return TypeTree::new(); | |
| 2516 | } | |
| 2517 | let element_tree = | |
| 2518 | typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); | |
| 2519 | let mut types = Vec::new(); | |
| 2520 | for elem_type in &element_tree.0 { | |
| 2521 | types.push(Type { | |
| 2522 | offset: -1, | |
| 2523 | size: elem_type.size, | |
| 2524 | kind: elem_type.kind, | |
| 2525 | child: elem_type.child.clone(), | |
| 2526 | }); | |
| 2527 | } | |
| 2528 | ||
| 2529 | return TypeTree(types); | |
| 2530 | } | |
| 2531 | } | |
| 2532 | ||
| 2533 | if ty.is_slice() { | |
| 2534 | if let ty::Slice(element_ty) = ty.kind() { | |
| 2535 | let element_tree = | |
| 2536 | typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); | |
| 2537 | return element_tree; | |
| 2538 | } | |
| 2539 | } | |
| 2540 | ||
| 2541 | if let ty::Tuple(tuple_types) = ty.kind() { | |
| 2542 | if tuple_types.is_empty() { | |
| 2543 | return TypeTree::new(); | |
| 2544 | } | |
| 2545 | ||
| 2546 | let mut types = Vec::new(); | |
| 2547 | let mut current_offset = 0; | |
| 2548 | ||
| 2549 | for tuple_ty in tuple_types.iter() { | |
| 2550 | let element_tree = | |
| 2551 | typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false); | |
| 2552 | ||
| 2553 | let element_layout = tcx | |
| 2554 | .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty)) | |
| 2555 | .ok() | |
| 2556 | .map(|layout| layout.size.bytes_usize()) | |
| 2557 | .unwrap_or(0); | |
| 2558 | ||
| 2559 | for elem_type in &element_tree.0 { | |
| 2560 | types.push(Type { | |
| 2561 | offset: if elem_type.offset == -1 { | |
| 2562 | current_offset as isize | |
| 2563 | } else { | |
| 2564 | current_offset as isize + elem_type.offset | |
| 2565 | }, | |
| 2566 | size: elem_type.size, | |
| 2567 | kind: elem_type.kind, | |
| 2568 | child: elem_type.child.clone(), | |
| 2569 | }); | |
| 2570 | } | |
| 2571 | ||
| 2572 | current_offset += element_layout; | |
| 2573 | } | |
| 2574 | ||
| 2575 | return TypeTree(types); | |
| 2576 | } | |
| 2577 | ||
| 2578 | if let ty::Adt(adt_def, args) = ty.kind() { | |
| 2579 | if adt_def.is_struct() { | |
| 2580 | let struct_layout = | |
| 2581 | tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)); | |
| 2582 | if let Ok(layout) = struct_layout { | |
| 2583 | let mut types = Vec::new(); | |
| 2584 | ||
| 2585 | for (field_idx, field_def) in adt_def.all_fields().enumerate() { | |
| 2586 | let field_ty = field_def.ty(tcx, args); | |
| 2587 | let field_tree = typetree_from_ty_impl_inner( | |
| 2588 | tcx, | |
| 2589 | field_ty.skip_norm_wip(), | |
| 2590 | depth + 1, | |
| 2591 | visited, | |
| 2592 | false, | |
| 2593 | ); | |
| 2594 | ||
| 2595 | let field_offset = layout.fields.offset(field_idx).bytes_usize(); | |
| 2596 | ||
| 2597 | for elem_type in &field_tree.0 { | |
| 2598 | types.push(Type { | |
| 2599 | offset: if elem_type.offset == -1 { | |
| 2600 | field_offset as isize | |
| 2601 | } else { | |
| 2602 | field_offset as isize + elem_type.offset | |
| 2603 | }, | |
| 2604 | size: elem_type.size, | |
| 2605 | kind: elem_type.kind, | |
| 2606 | child: elem_type.child.clone(), | |
| 2607 | }); | |
| 2608 | } | |
| 2609 | } | |
| 2610 | ||
| 2611 | return TypeTree(types); | |
| 2612 | } | |
| 2613 | } | |
| 2614 | } | |
| 2615 | ||
| 2616 | TypeTree::new() | |
| 2617 | } |
compiler/rustc_middle/src/ty/typetree.rs created+208| ... | ... | @@ -0,0 +1,208 @@ |
| 1 | use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; | |
| 2 | use tracing::trace; | |
| 3 | ||
| 4 | use crate::ty::context::TyCtxt; | |
| 5 | use crate::ty::{self, Ty}; | |
| 6 | ||
| 7 | /// Generate TypeTree information for autodiff. | |
| 8 | /// This function creates TypeTree metadata that describes the memory layout | |
| 9 | /// of function parameters and return types for Enzyme autodiff. | |
| 10 | pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree { | |
| 11 | // Check if TypeTrees are disabled via NoTT flag | |
| 12 | if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) { | |
| 13 | return FncTree { args: vec![], ret: TypeTree::new() }; | |
| 14 | } | |
| 15 | ||
| 16 | // Check if this is actually a function type | |
| 17 | if !fn_ty.is_fn() { | |
| 18 | return FncTree { args: vec![], ret: TypeTree::new() }; | |
| 19 | } | |
| 20 | ||
| 21 | // Get the function signature | |
| 22 | let fn_sig = fn_ty.fn_sig(tcx); | |
| 23 | let sig = tcx.instantiate_bound_regions_with_erased(fn_sig); | |
| 24 | ||
| 25 | // Create TypeTrees for each input parameter | |
| 26 | let mut args = vec![]; | |
| 27 | for ty in sig.inputs().iter() { | |
| 28 | let type_tree = typetree_from_ty(tcx, *ty); | |
| 29 | args.push(type_tree); | |
| 30 | } | |
| 31 | ||
| 32 | // Create TypeTree for return type | |
| 33 | let ret = typetree_from_ty(tcx, sig.output()); | |
| 34 | ||
| 35 | FncTree { args, ret } | |
| 36 | } | |
| 37 | ||
| 38 | /// Generate a TypeTree for a specific type. | |
| 39 | /// Mainly a convenience wrapper around the actual implementation. | |
| 40 | pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { | |
| 41 | let mut visited = Vec::new(); | |
| 42 | typetree_from_ty_impl_inner(tcx, ty, 0, &mut visited, false) | |
| 43 | } | |
| 44 | ||
| 45 | /// Maximum recursion depth for TypeTree generation to prevent stack overflow | |
| 46 | /// from pathological deeply nested types. Combined with cycle detection. | |
| 47 | const MAX_TYPETREE_DEPTH: usize = 6; | |
| 48 | ||
| 49 | /// Internal implementation with context about whether this is for a reference target. | |
| 50 | fn typetree_from_ty_impl_inner<'tcx>( | |
| 51 | tcx: TyCtxt<'tcx>, | |
| 52 | ty: Ty<'tcx>, | |
| 53 | depth: usize, | |
| 54 | visited: &mut Vec<Ty<'tcx>>, | |
| 55 | is_reference_target: bool, | |
| 56 | ) -> TypeTree { | |
| 57 | if depth >= MAX_TYPETREE_DEPTH { | |
| 58 | trace!("typetree depth limit {} reached for type: {}", MAX_TYPETREE_DEPTH, ty); | |
| 59 | return TypeTree::new(); | |
| 60 | } | |
| 61 | ||
| 62 | if visited.contains(&ty) { | |
| 63 | return TypeTree::new(); | |
| 64 | } | |
| 65 | visited.push(ty); | |
| 66 | ||
| 67 | if ty.is_scalar() { | |
| 68 | let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { | |
| 69 | (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) | |
| 70 | } else if ty.is_floating_point() { | |
| 71 | match ty { | |
| 72 | x if x == tcx.types.f16 => (Kind::Half, 2), | |
| 73 | x if x == tcx.types.f32 => (Kind::Float, 4), | |
| 74 | x if x == tcx.types.f64 => (Kind::Double, 8), | |
| 75 | x if x == tcx.types.f128 => (Kind::F128, 16), | |
| 76 | _ => (Kind::Integer, 0), | |
| 77 | } | |
| 78 | } else { | |
| 79 | (Kind::Integer, 0) | |
| 80 | }; | |
| 81 | ||
| 82 | // Use offset 0 for scalars that are direct targets of references (like &f64) | |
| 83 | // Use offset -1 for scalars used directly (like function return types) | |
| 84 | let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 }; | |
| 85 | return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]); | |
| 86 | } | |
| 87 | ||
| 88 | if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { | |
| 89 | let Some(inner_ty) = ty.builtin_deref(true) else { | |
| 90 | return TypeTree::new(); | |
| 91 | }; | |
| 92 | ||
| 93 | let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true); | |
| 94 | return TypeTree(vec![Type { | |
| 95 | offset: -1, | |
| 96 | size: tcx.data_layout.pointer_size().bytes_usize(), | |
| 97 | kind: Kind::Pointer, | |
| 98 | child, | |
| 99 | }]); | |
| 100 | } | |
| 101 | ||
| 102 | if ty.is_array() { | |
| 103 | if let ty::Array(element_ty, len_const) = ty.kind() { | |
| 104 | let len = len_const.try_to_target_usize(tcx).unwrap_or(0); | |
| 105 | if len == 0 { | |
| 106 | return TypeTree::new(); | |
| 107 | } | |
| 108 | let element_tree = | |
| 109 | typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); | |
| 110 | let mut types = Vec::new(); | |
| 111 | for elem_type in &element_tree.0 { | |
| 112 | types.push(Type { | |
| 113 | offset: -1, | |
| 114 | size: elem_type.size, | |
| 115 | kind: elem_type.kind, | |
| 116 | child: elem_type.child.clone(), | |
| 117 | }); | |
| 118 | } | |
| 119 | ||
| 120 | return TypeTree(types); | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | if ty.is_slice() { | |
| 125 | if let ty::Slice(element_ty) = ty.kind() { | |
| 126 | let element_tree = | |
| 127 | typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); | |
| 128 | return element_tree; | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | if let ty::Tuple(tuple_types) = ty.kind() { | |
| 133 | if tuple_types.is_empty() { | |
| 134 | return TypeTree::new(); | |
| 135 | } | |
| 136 | ||
| 137 | let mut types = Vec::new(); | |
| 138 | let mut current_offset = 0; | |
| 139 | ||
| 140 | for tuple_ty in tuple_types.iter() { | |
| 141 | let element_tree = | |
| 142 | typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false); | |
| 143 | ||
| 144 | let element_layout = tcx | |
| 145 | .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty)) | |
| 146 | .ok() | |
| 147 | .map(|layout| layout.size.bytes_usize()) | |
| 148 | .unwrap_or(0); | |
| 149 | ||
| 150 | for elem_type in &element_tree.0 { | |
| 151 | types.push(Type { | |
| 152 | offset: if elem_type.offset == -1 { | |
| 153 | current_offset as isize | |
| 154 | } else { | |
| 155 | current_offset as isize + elem_type.offset | |
| 156 | }, | |
| 157 | size: elem_type.size, | |
| 158 | kind: elem_type.kind, | |
| 159 | child: elem_type.child.clone(), | |
| 160 | }); | |
| 161 | } | |
| 162 | ||
| 163 | current_offset += element_layout; | |
| 164 | } | |
| 165 | ||
| 166 | return TypeTree(types); | |
| 167 | } | |
| 168 | ||
| 169 | if let ty::Adt(adt_def, args) = ty.kind() { | |
| 170 | if adt_def.is_struct() { | |
| 171 | let struct_layout = | |
| 172 | tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)); | |
| 173 | if let Ok(layout) = struct_layout { | |
| 174 | let mut types = Vec::new(); | |
| 175 | ||
| 176 | for (field_idx, field_def) in adt_def.all_fields().enumerate() { | |
| 177 | let field_ty = field_def.ty(tcx, args); | |
| 178 | let field_tree = typetree_from_ty_impl_inner( | |
| 179 | tcx, | |
| 180 | field_ty.skip_norm_wip(), | |
| 181 | depth + 1, | |
| 182 | visited, | |
| 183 | false, | |
| 184 | ); | |
| 185 | ||
| 186 | let field_offset = layout.fields.offset(field_idx).bytes_usize(); | |
| 187 | ||
| 188 | for elem_type in &field_tree.0 { | |
| 189 | types.push(Type { | |
| 190 | offset: if elem_type.offset == -1 { | |
| 191 | field_offset as isize | |
| 192 | } else { | |
| 193 | field_offset as isize + elem_type.offset | |
| 194 | }, | |
| 195 | size: elem_type.size, | |
| 196 | kind: elem_type.kind, | |
| 197 | child: elem_type.child.clone(), | |
| 198 | }); | |
| 199 | } | |
| 200 | } | |
| 201 | ||
| 202 | return TypeTree(types); | |
| 203 | } | |
| 204 | } | |
| 205 | } | |
| 206 | ||
| 207 | TypeTree::new() | |
| 208 | } |
compiler/rustc_trait_selection/src/traits/auto_trait.rs+7-2| ... | ... | @@ -607,6 +607,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { |
| 607 | 607 | // if possible. |
| 608 | 608 | predicates.push_back(bound_predicate.rebind(p)); |
| 609 | 609 | } |
| 610 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(p)) => { | |
| 611 | let p = bound_predicate.rebind(p); | |
| 612 | if self.is_param_no_infer(p.skip_binder().trait_ref.args) && is_new_pred { | |
| 613 | self.add_user_pred(computed_preds, predicate); | |
| 614 | } | |
| 615 | } | |
| 610 | 616 | ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { |
| 611 | 617 | let p = bound_predicate.rebind(p); |
| 612 | 618 | debug!( |
| ... | ... | @@ -811,8 +817,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { |
| 811 | 817 | | ty::PredicateKind::DynCompatible(..) |
| 812 | 818 | | ty::PredicateKind::Subtype(..) |
| 813 | 819 | | ty::PredicateKind::Coerce(..) |
| 814 | | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | |
| 815 | | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} | |
| 820 | | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => {} | |
| 816 | 821 | ty::PredicateKind::Ambiguous => return false, |
| 817 | 822 | |
| 818 | 823 | // FIXME(generic_const_exprs): you can absolutely add this as a where clauses |
library/core/src/mem/maybe_uninit.rs+3-3| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | use crate::any::type_name; |
| 2 | 2 | use crate::clone::TrivialClone; |
| 3 | 3 | use crate::marker::Destruct; |
| 4 | use crate::mem::ManuallyDrop; | |
| 4 | use crate::mem::{ManuallyDrop, transmute_neo}; | |
| 5 | 5 | use crate::{fmt, intrinsics, ptr, slice}; |
| 6 | 6 | |
| 7 | 7 | /// A wrapper type to construct uninitialized instances of `T`. |
| ... | ... | @@ -724,9 +724,9 @@ impl<T> MaybeUninit<T> { |
| 724 | 724 | // This also means that `self` must be a `value` variant. |
| 725 | 725 | unsafe { |
| 726 | 726 | intrinsics::assert_inhabited::<T>(); |
| 727 | // We do this via a raw ptr read instead of `ManuallyDrop::into_inner` so that there's | |
| 727 | // We do this via a transmute instead of `ManuallyDrop::into_inner` so that there's | |
| 728 | 728 | // no trace of `ManuallyDrop` in Miri's error messages here. |
| 729 | (&raw const self.value).cast::<T>().read() | |
| 729 | transmute_neo(self) | |
| 730 | 730 | } |
| 731 | 731 | } |
| 732 | 732 |
library/core/src/mem/mod.rs+5| ... | ... | @@ -1196,6 +1196,9 @@ pub const unsafe fn transmute_prefix<Src, Dst>(src: Src) -> Dst { |
| 1196 | 1196 | /// New version of `transmute`, exposed under this name so it can be iterated upon |
| 1197 | 1197 | /// without risking breakage to uses of "real" transmute. |
| 1198 | 1198 | /// |
| 1199 | /// Uses a `const`-`assert` to check the sizes instead of typeck hacks, | |
| 1200 | /// but is semantially identical to `transmute` otherwise. | |
| 1201 | /// | |
| 1199 | 1202 | /// It will not be stabilized under this name. |
| 1200 | 1203 | /// |
| 1201 | 1204 | /// # Examples |
| ... | ... | @@ -1214,6 +1217,8 @@ pub const unsafe fn transmute_prefix<Src, Dst>(src: Src) -> Dst { |
| 1214 | 1217 | /// unsafe { transmute_neo::<u32, u16>(123) }; |
| 1215 | 1218 | /// ``` |
| 1216 | 1219 | #[unstable(feature = "transmute_neo", issue = "155079")] |
| 1220 | #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | |
| 1221 | #[inline] | |
| 1217 | 1222 | pub const unsafe fn transmute_neo<Src, Dst>(src: Src) -> Dst { |
| 1218 | 1223 | const { assert!(Src::SIZE == Dst::SIZE) }; |
| 1219 | 1224 |
library/std/src/panicking.rs+13-1| ... | ... | @@ -415,6 +415,7 @@ pub mod panic_count { |
| 415 | 415 | // |
| 416 | 416 | // This also updates thread-local state to keep track of whether a panic |
| 417 | 417 | // hook is currently executing. |
| 418 | #[must_use = "MustAbort may not be ignored"] | |
| 418 | 419 | pub fn increase(run_panic_hook: bool) -> Option<MustAbort> { |
| 419 | 420 | let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed); |
| 420 | 421 | if global_count & ALWAYS_ABORT_FLAG != 0 { |
| ... | ... | @@ -843,7 +844,18 @@ fn panic_with_hook( |
| 843 | 844 | /// It just forwards the payload to the panic runtime. |
| 844 | 845 | #[cfg_attr(panic = "immediate-abort", inline)] |
| 845 | 846 | pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! { |
| 846 | panic_count::increase(false); | |
| 847 | if let Some(must_abort) = panic_count::increase(false) { | |
| 848 | match must_abort { | |
| 849 | panic_count::MustAbort::PanicInHook => { | |
| 850 | rtprintpanic!("thread panicked while processing panic. aborting.\n"); | |
| 851 | } | |
| 852 | panic_count::MustAbort::AlwaysAbort => { | |
| 853 | rtprintpanic!("aborting due to panic\n"); | |
| 854 | } | |
| 855 | } | |
| 856 | ||
| 857 | crate::process::abort(); | |
| 858 | } | |
| 847 | 859 | |
| 848 | 860 | struct RewrapBox(Box<dyn Any + Send>); |
| 849 | 861 |
src/bootstrap/src/core/build_steps/llvm.rs+5-5| ... | ... | @@ -169,7 +169,7 @@ pub fn prebuilt_llvm_config( |
| 169 | 169 | generate_smart_stamp_hash( |
| 170 | 170 | builder, |
| 171 | 171 | &builder.config.src.join("src/llvm-project"), |
| 172 | &builder.llvm_cache_key(), | |
| 172 | builder.in_tree_llvm_info.sha().unwrap_or_default(), | |
| 173 | 173 | ) |
| 174 | 174 | }); |
| 175 | 175 | |
| ... | ... | @@ -999,7 +999,7 @@ impl Step for OmpOffload { |
| 999 | 999 | generate_smart_stamp_hash( |
| 1000 | 1000 | builder, |
| 1001 | 1001 | &builder.config.src.join("src/llvm-project/offload"), |
| 1002 | &builder.llvm_cache_key(), | |
| 1002 | builder.in_tree_llvm_info.sha().unwrap_or_default(), | |
| 1003 | 1003 | ) |
| 1004 | 1004 | }); |
| 1005 | 1005 | let stamp = BuildStamp::new(&out_dir).with_prefix("offload").add_stamp(smart_stamp_hash); |
| ... | ... | @@ -1166,8 +1166,8 @@ impl Step for Enzyme { |
| 1166 | 1166 | // Enzyme links against LLVM. If we update the LLVM submodule libLLVM might get a new |
| 1167 | 1167 | // version number, in which case Enzyme will now fail to find LLVM. By including the LLVM |
| 1168 | 1168 | // hash into the Enzyme hash we force a rebuild of Enzyme when updating LLVM. |
| 1169 | let enzyme_hash_input = | |
| 1170 | builder.llvm_cache_key() + builder.enzyme_info.sha().unwrap_or_default(); | |
| 1169 | let enzyme_hash_input = builder.in_tree_llvm_info.sha().unwrap_or_default().to_owned() | |
| 1170 | + builder.enzyme_info.sha().unwrap_or_default(); | |
| 1171 | 1171 | |
| 1172 | 1172 | static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); |
| 1173 | 1173 | let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { |
| ... | ... | @@ -1430,7 +1430,7 @@ impl Step for Sanitizers { |
| 1430 | 1430 | generate_smart_stamp_hash( |
| 1431 | 1431 | builder, |
| 1432 | 1432 | &builder.config.src.join("src/llvm-project/compiler-rt"), |
| 1433 | &builder.llvm_cache_key(), | |
| 1433 | builder.in_tree_llvm_info.sha().unwrap_or_default(), | |
| 1434 | 1434 | ) |
| 1435 | 1435 | }); |
| 1436 | 1436 |
src/bootstrap/src/core/builder/mod.rs-10| ... | ... | @@ -1687,16 +1687,6 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler |
| 1687 | 1687 | pub fn exec_ctx(&self) -> &ExecutionContext { |
| 1688 | 1688 | &self.config.exec_ctx |
| 1689 | 1689 | } |
| 1690 | ||
| 1691 | /// When to rebuild LLVM. Currently includes the LLVM commit hash and the configuration from | |
| 1692 | /// bootstrap.toml. | |
| 1693 | pub(crate) fn llvm_cache_key(&self) -> String { | |
| 1694 | format!( | |
| 1695 | "sha={sha}\nkey={key}", | |
| 1696 | sha = self.in_tree_llvm_info.sha().unwrap_or_default(), | |
| 1697 | key = self.config.llvm_cache_key, | |
| 1698 | ) | |
| 1699 | } | |
| 1700 | 1690 | } |
| 1701 | 1691 | |
| 1702 | 1692 | /// Return qualified step name, e.g. `compile::Rustc`. |
src/bootstrap/src/core/config/config.rs+1-7| ... | ... | @@ -156,9 +156,6 @@ pub struct Config { |
| 156 | 156 | pub backtrace_on_ice: bool, |
| 157 | 157 | |
| 158 | 158 | // llvm codegen options |
| 159 | /// Key used to decide when to rebuild LLVM. | |
| 160 | pub llvm_cache_key: String, | |
| 161 | ||
| 162 | 159 | pub llvm_assertions: bool, |
| 163 | 160 | pub llvm_tests: bool, |
| 164 | 161 | pub llvm_enzyme: bool, |
| ... | ... | @@ -598,8 +595,6 @@ impl Config { |
| 598 | 595 | rustflags: rust_rustflags, |
| 599 | 596 | } = toml.rust.unwrap_or_default(); |
| 600 | 597 | |
| 601 | let llvm = toml.llvm.unwrap_or_default(); | |
| 602 | let llvm_cache_key = llvm.cache_key(); | |
| 603 | 598 | let Llvm { |
| 604 | 599 | optimize: llvm_optimize, |
| 605 | 600 | thin_lto: llvm_thin_lto, |
| ... | ... | @@ -630,7 +625,7 @@ impl Config { |
| 630 | 625 | enable_warnings: llvm_enable_warnings, |
| 631 | 626 | download_ci_llvm: llvm_download_ci_llvm, |
| 632 | 627 | build_config: llvm_build_config, |
| 633 | } = llvm; | |
| 628 | } = toml.llvm.unwrap_or_default(); | |
| 634 | 629 | |
| 635 | 630 | let Dist { |
| 636 | 631 | sign_folder: dist_sign_folder, |
| ... | ... | @@ -1406,7 +1401,6 @@ impl Config { |
| 1406 | 1401 | llvm_assertions, |
| 1407 | 1402 | llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false), |
| 1408 | 1403 | llvm_build_config: llvm_build_config.clone().unwrap_or(Default::default()), |
| 1409 | llvm_cache_key, | |
| 1410 | 1404 | llvm_cflags, |
| 1411 | 1405 | llvm_clang: llvm_clang.unwrap_or(false), |
| 1412 | 1406 | llvm_clang_cl, |
src/bootstrap/src/core/config/toml/llvm.rs-87| ... | ... | @@ -43,93 +43,6 @@ define_config! { |
| 43 | 43 | } |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | impl Llvm { | |
| 47 | /// A key that is used to determine whether LLVM should be rebuilt. | |
| 48 | pub(crate) fn cache_key(&self) -> String { | |
| 49 | let helper = || { | |
| 50 | let mut key = String::with_capacity(512); | |
| 51 | ||
| 52 | let Self { | |
| 53 | optimize, | |
| 54 | thin_lto, | |
| 55 | release_debuginfo, | |
| 56 | assertions, | |
| 57 | tests, | |
| 58 | enzyme, | |
| 59 | plugins, | |
| 60 | static_libstdcpp, | |
| 61 | libzstd, | |
| 62 | ninja, | |
| 63 | targets, | |
| 64 | experimental_targets, | |
| 65 | link_jobs: _, | |
| 66 | link_shared, | |
| 67 | version_suffix, | |
| 68 | clang_cl, | |
| 69 | cflags, | |
| 70 | cxxflags, | |
| 71 | ldflags, | |
| 72 | use_libcxx, | |
| 73 | use_linker, | |
| 74 | allow_old_toolchain, | |
| 75 | offload, | |
| 76 | polly, | |
| 77 | offload_clang_dir, | |
| 78 | clang, | |
| 79 | enable_warnings: _, | |
| 80 | build_config, | |
| 81 | download_ci_llvm: _, | |
| 82 | } = self; | |
| 83 | ||
| 84 | use std::fmt::Write; | |
| 85 | write!(key, "{:?}", optimize)?; | |
| 86 | write!(key, "{:?}", thin_lto)?; | |
| 87 | write!(key, "{:?}", release_debuginfo)?; | |
| 88 | write!(key, "{:?}", assertions)?; | |
| 89 | write!(key, "{:?}", tests)?; | |
| 90 | write!(key, "{:?}", enzyme)?; | |
| 91 | write!(key, "{:?}", plugins)?; | |
| 92 | write!(key, "{:?}", static_libstdcpp)?; | |
| 93 | write!(key, "{:?}", libzstd)?; | |
| 94 | write!(key, "{:?}", ninja)?; | |
| 95 | write!(key, "{:?}", targets)?; | |
| 96 | write!(key, "{:?}", experimental_targets)?; | |
| 97 | write!(key, "{:?}", link_shared)?; | |
| 98 | write!(key, "{:?}", version_suffix)?; | |
| 99 | write!(key, "{:?}", clang_cl)?; | |
| 100 | write!(key, "{:?}", cflags)?; | |
| 101 | write!(key, "{:?}", cxxflags)?; | |
| 102 | write!(key, "{:?}", ldflags)?; | |
| 103 | write!(key, "{:?}", use_libcxx)?; | |
| 104 | write!(key, "{:?}", use_linker)?; | |
| 105 | write!(key, "{:?}", allow_old_toolchain)?; | |
| 106 | write!(key, "{:?}", offload)?; | |
| 107 | write!(key, "{:?}", polly)?; | |
| 108 | write!(key, "{:?}", offload_clang_dir)?; | |
| 109 | write!(key, "{:?}", clang)?; | |
| 110 | ||
| 111 | match build_config { | |
| 112 | None => { | |
| 113 | write!(key, "None")?; | |
| 114 | } | |
| 115 | Some(c) => { | |
| 116 | let mut build_config = c.iter().collect::<Vec<_>>(); | |
| 117 | build_config.sort(); | |
| 118 | ||
| 119 | for (k, v) in build_config { | |
| 120 | write!(key, "{}: {}", k, v)?; | |
| 121 | } | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | Ok::<_, std::fmt::Error>(key) | |
| 126 | }; | |
| 127 | ||
| 128 | // write! to a String always succeeds unless OOM. | |
| 129 | helper().unwrap() | |
| 130 | } | |
| 131 | } | |
| 132 | ||
| 133 | 46 | /// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. |
| 134 | 47 | /// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing. |
| 135 | 48 | #[cfg(not(test))] |
src/doc/unstable-book/src/compiler-flags/default-visibility.md+1-1| ... | ... | @@ -41,4 +41,4 @@ building for Linux. Other linkers such as LLD are not affected. |
| 41 | 41 | Using `-Zdefault-visibility=interposable` will cause symbols to be emitted with "default" |
| 42 | 42 | visibility. On platforms that support it, this makes it so that symbols can be interposed, which |
| 43 | 43 | means that they can be overridden by symbols with the same name from the executable or by other |
| 44 | shared objects earier in the load order. | |
| 44 | shared objects earlier in the load order. |
src/librustdoc/html/static/js/search.js+2-2| ... | ... | @@ -5185,9 +5185,9 @@ function makeTab(tabNb, text, results, query, isTypeSearch, goToFirst) { |
| 5185 | 5185 | errorReport.className = "error"; |
| 5186 | 5186 | errorReport.innerHTML = `Query parser error: "${error.join("")}".`; |
| 5187 | 5187 | search.insertBefore(errorReport, search.firstElementChild); |
| 5188 | } else if (goToFirst || | |
| 5188 | } else if (tabNb === 0 && (goToFirst || | |
| 5189 | 5189 | (count === 1 && getSettingValue("go-to-only-result") === "true") |
| 5190 | ) { | |
| 5190 | )) { | |
| 5191 | 5191 | // Needed to force re-execution of JS when coming back to a page. Let's take this |
| 5192 | 5192 | // scenario as example: |
| 5193 | 5193 | // |
src/librustdoc/json/conversions.rs+74-2| ... | ... | @@ -8,9 +8,9 @@ use rustc_data_structures::fx::FxHashSet; |
| 8 | 8 | use rustc_data_structures::thin_vec::ThinVec; |
| 9 | 9 | use rustc_hir as hir; |
| 10 | 10 | use rustc_hir::attrs::{self, DeprecatedSince, DocAttribute, DocInline, HideOrShow}; |
| 11 | use rustc_hir::def::CtorKind; | |
| 11 | use rustc_hir::def::{CtorKind, DefKind}; | |
| 12 | 12 | use rustc_hir::def_id::DefId; |
| 13 | use rustc_hir::{HeaderSafety, Safety}; | |
| 13 | use rustc_hir::{HeaderSafety, Safety, find_attr}; | |
| 14 | 14 | use rustc_metadata::rendered_const; |
| 15 | 15 | use rustc_middle::ty::TyCtxt; |
| 16 | 16 | use rustc_middle::{bug, ty}; |
| ... | ... | @@ -92,6 +92,9 @@ impl JsonRenderer<'_> { |
| 92 | 92 | item.item_id.as_def_id() |
| 93 | 93 | }; |
| 94 | 94 | let stability = stability_def_id.and_then(|def_id| self.tcx.lookup_stability(def_id)); |
| 95 | let const_stability = item.item_id.as_def_id().and_then(|def_id| { | |
| 96 | const_stability_for_def_id(self.tcx, def_id).map(|s| Box::new(s.into_json(self))) | |
| 97 | }); | |
| 95 | 98 | |
| 96 | 99 | Some(Item { |
| 97 | 100 | id, |
| ... | ... | @@ -100,6 +103,7 @@ impl JsonRenderer<'_> { |
| 100 | 103 | span: span.and_then(|span| span.into_json(self)), |
| 101 | 104 | visibility: visibility.into_json(self), |
| 102 | 105 | stability: stability.map(|s| Box::new(s.into_json(self))), |
| 106 | const_stability, | |
| 103 | 107 | docs, |
| 104 | 108 | attrs, |
| 105 | 109 | deprecation: deprecation.into_json(self), |
| ... | ... | @@ -246,6 +250,24 @@ impl FromClean<hir::Stability> for Stability { |
| 246 | 250 | } |
| 247 | 251 | } |
| 248 | 252 | |
| 253 | impl FromClean<hir::ConstStability> for Stability { | |
| 254 | fn from_clean(stab: &hir::ConstStability, _renderer: &JsonRenderer<'_>) -> Self { | |
| 255 | let feature = stab.feature.to_string(); | |
| 256 | let level = match stab.level { | |
| 257 | hir::StabilityLevel::Stable { since, .. } => StabilityLevel::Stable { | |
| 258 | since: match since { | |
| 259 | hir::StableSince::Version(since) => Some(since.to_string()), | |
| 260 | hir::StableSince::Current => Some(hir::RustcVersion::CURRENT.to_string()), | |
| 261 | // Match rustdoc HTML: malformed stable-since values are omitted. | |
| 262 | hir::StableSince::Err(_) => None, | |
| 263 | }, | |
| 264 | }, | |
| 265 | hir::StabilityLevel::Unstable { .. } => StabilityLevel::Unstable, | |
| 266 | }; | |
| 267 | Stability { feature, level } | |
| 268 | } | |
| 269 | } | |
| 270 | ||
| 249 | 271 | impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> { |
| 250 | 272 | fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { |
| 251 | 273 | use clean::GenericArgs::*; |
| ... | ... | @@ -948,6 +970,55 @@ impl FromClean<ItemType> for ItemKind { |
| 948 | 970 | } |
| 949 | 971 | } |
| 950 | 972 | |
| 973 | fn const_stability_for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::ConstStability> { | |
| 974 | if !tcx.is_conditionally_const(def_id) { | |
| 975 | // The item cannot be conditionally-const. No const stability here. | |
| 976 | // | |
| 977 | // This includes associated consts, which are an interesting exception | |
| 978 | // to the general rule that items inside `const impl` and `const trait` carry | |
| 979 | // the const-stability of that block. Associated consts are already const, always. | |
| 980 | return None; | |
| 981 | } | |
| 982 | ||
| 983 | let const_stability = tcx.lookup_const_stability(def_id)?; | |
| 984 | if find_attr!(tcx, def_id, RustcConstStability { .. }) { | |
| 985 | // Direct const-stability attribute on the item itself. Return it directly. | |
| 986 | return Some(const_stability); | |
| 987 | } | |
| 988 | ||
| 989 | if const_stability.is_const_stable() { | |
| 990 | // Items that are const-stable without an explicit attribute on their own item | |
| 991 | // must be associated items inside `const trait` or `const impl`. | |
| 992 | // We don't want to duplicate their parent item's const-stability attribute. | |
| 993 | return None; | |
| 994 | } | |
| 995 | ||
| 996 | // We're dealing with an item that is const-unstable, | |
| 997 | // but doesn't have an explicit const-stability attribute on it. | |
| 998 | // | |
| 999 | // Today, this means one of two cases: | |
| 1000 | // - The item is enclosed within a `#[rustc_const_unstable]` block, | |
| 1001 | // like a `const trait` or `const impl`, in which case our query propagated the parent's | |
| 1002 | // const-instability info. This const-instability is desirable to place into JSON | |
| 1003 | // because *only some* associated items inside such a block are const-unstable. | |
| 1004 | // Associated consts are the exception, and were handled earlier. | |
| 1005 | // - The item is `#[unstable]` which implies it's const-unstable under the same feature, | |
| 1006 | // in which case we don't want to duplicate the existing stability attribute | |
| 1007 | // which would already appear in an adjacent field in the JSON anyway. | |
| 1008 | if let Some(parent_def_id) = tcx.opt_parent(def_id) | |
| 1009 | && matches!(tcx.def_kind(parent_def_id), DefKind::Trait | DefKind::Impl { .. }) | |
| 1010 | && tcx.lookup_const_stability(parent_def_id) == Some(const_stability) | |
| 1011 | { | |
| 1012 | Some(const_stability) | |
| 1013 | } else { | |
| 1014 | std::debug_assert_matches!( | |
| 1015 | tcx.lookup_stability(def_id).map(|s| s.level), | |
| 1016 | Some(hir::StabilityLevel::Unstable { .. }) | |
| 1017 | ); | |
| 1018 | None | |
| 1019 | } | |
| 1020 | } | |
| 1021 | ||
| 951 | 1022 | /// Maybe convert a attribute from hir to json. |
| 952 | 1023 | /// |
| 953 | 1024 | /// Returns `None` if the attribute shouldn't be in the output. |
| ... | ... | @@ -966,6 +1037,7 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>) |
| 966 | 1037 | vec![match kind { |
| 967 | 1038 | AK::Deprecated { .. } => return Vec::new(), // Handled separately into Item::deprecation. |
| 968 | 1039 | AK::Stability { .. } => return Vec::new(), // Handled separately into Item::stability |
| 1040 | AK::RustcConstStability { .. } => return Vec::new(), // Handled separately into Item::const_stability. | |
| 969 | 1041 | |
| 970 | 1042 | AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), |
| 971 | 1043 |
src/librustdoc/json/mod.rs+1-1| ... | ... | @@ -361,6 +361,6 @@ mod size_asserts { |
| 361 | 361 | // tidy-alphabetical-end |
| 362 | 362 | |
| 363 | 363 | // These contains a `PathBuf`, which is different sizes on different OSes. |
| 364 | static_assert_size!(Item, 536 + size_of::<std::path::PathBuf>()); | |
| 364 | static_assert_size!(Item, 544 + size_of::<std::path::PathBuf>()); | |
| 365 | 365 | static_assert_size!(ExternalCrate, 48 + size_of::<std::path::PathBuf>()); |
| 366 | 366 | } |
src/rustdoc-json-types/lib.rs+21-7| ... | ... | @@ -114,8 +114,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc |
| 114 | 114 | // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line |
| 115 | 115 | // are deliberately not in a doc comment, because they need not be in public docs.) |
| 116 | 116 | // |
| 117 | // Latest feature: Add `Item::stability`. | |
| 118 | pub const FORMAT_VERSION: u32 = 58; | |
| 117 | // Latest feature: Add `Item::const_stability`. | |
| 118 | pub const FORMAT_VERSION: u32 = 59; | |
| 119 | 119 | |
| 120 | 120 | /// The root of the emitted JSON blob. |
| 121 | 121 | /// |
| ... | ... | @@ -286,6 +286,8 @@ pub struct Item { |
| 286 | 286 | /// - `#[doc = "Doc Comment"]` or `/// Doc comment`: see [`Self::docs`] instead. |
| 287 | 287 | /// - `#[deprecated]` attributes: see the [`Self::deprecation`] field instead. |
| 288 | 288 | /// - `#[stable]` and `#[unstable]` attributes: see the [`Self::stability`] field instead. |
| 289 | /// - `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes: | |
| 290 | /// see the [`Self::const_stability`] field instead. | |
| 289 | 291 | /// |
| 290 | 292 | /// Attributes appear in pretty-printed Rust form, regardless of their formatting |
| 291 | 293 | /// in the original source code. For example: |
| ... | ... | @@ -319,20 +321,31 @@ pub struct Item { |
| 319 | 321 | /// most ordinary third-party crates usually have no data here. |
| 320 | 322 | pub stability: Option<Box<Stability>>, |
| 321 | 323 | |
| 324 | /// Stability information for using this item in const contexts, if any. | |
| 325 | /// | |
| 326 | /// This is separate from [`Self::stability`]. An item can be stable as regular API while its | |
| 327 | /// const use is unstable. An unstable item may have no separate const-stability value here. | |
| 328 | /// | |
| 329 | /// This field is only populated for item kinds whose const behavior can have separate | |
| 330 | /// stability information, such as const functions, const traits, const trait impls, | |
| 331 | /// and associated items whose const behavior is controlled by a const trait or const impl. | |
| 332 | pub const_stability: Option<Box<Stability>>, | |
| 333 | ||
| 322 | 334 | /// The type-specific fields describing this item. |
| 323 | 335 | pub inner: ItemEnum, |
| 324 | 336 | } |
| 325 | 337 | |
| 326 | 338 | /// Stability information for an item. |
| 327 | 339 | /// |
| 328 | /// This only refers to regular item stability: whether the item is stable or unstable | |
| 329 | /// as represented by the `#[stable]` or `#[unstable]` attributes. | |
| 330 | /// Const stability and default-body stability are different things and not captured here. | |
| 340 | /// In [`Item::stability`], this refers to regular item stability: whether the item is | |
| 341 | /// stable or unstable as represented by the `#[stable]` or `#[unstable]` attributes. | |
| 342 | /// In [`Item::const_stability`], this refers to using the item in const contexts, | |
| 343 | /// as represented by `#[rustc_const_stable]` or `#[rustc_const_unstable]`. | |
| 331 | 344 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 332 | 345 | #[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] |
| 333 | 346 | #[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] |
| 334 | 347 | pub struct Stability { |
| 335 | /// The stability feature associated with this item. | |
| 348 | /// The feature associated with this stability record. | |
| 336 | 349 | /// |
| 337 | 350 | /// For unstable items, this is the feature gate associated with the item. |
| 338 | 351 | /// For stable items, this is the historical label recorded when the item was stabilized. |
| ... | ... | @@ -342,7 +355,6 @@ pub struct Stability { |
| 342 | 355 | pub level: StabilityLevel, |
| 343 | 356 | } |
| 344 | 357 | |
| 345 | /// Whether an item is stable or unstable as regular public API. | |
| 346 | 358 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 347 | 359 | #[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] |
| 348 | 360 | #[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] |
| ... | ... | @@ -365,6 +377,8 @@ pub enum StabilityLevel { |
| 365 | 377 | /// - `#[doc = "Doc Comment"]` or `/// Doc comment`. These are in [`Item::docs`] instead. |
| 366 | 378 | /// - `#[deprecated]`. These are in [`Item::deprecation`] instead. |
| 367 | 379 | /// - `#[stable]` and `#[unstable]`. These are in [`Item::stability`] instead. |
| 380 | /// - `#[rustc_const_stable]` and `#[rustc_const_unstable]`. These are in | |
| 381 | /// [`Item::const_stability`] instead. | |
| 368 | 382 | pub enum Attribute { |
| 369 | 383 | /// `#[non_exhaustive]` |
| 370 | 384 | NonExhaustive, |
src/tools/jsondoclint/src/validator/tests.rs+7| ... | ... | @@ -34,6 +34,7 @@ fn errors_on_missing_links() { |
| 34 | 34 | attrs: vec![], |
| 35 | 35 | deprecation: None, |
| 36 | 36 | stability: None, |
| 37 | const_stability: None, | |
| 37 | 38 | inner: ItemEnum::Module(Module { |
| 38 | 39 | is_crate: true, |
| 39 | 40 | items: vec![], |
| ... | ... | @@ -83,6 +84,7 @@ fn errors_on_local_in_paths_and_not_index() { |
| 83 | 84 | attrs: Vec::new(), |
| 84 | 85 | deprecation: None, |
| 85 | 86 | stability: None, |
| 87 | const_stability: None, | |
| 86 | 88 | inner: ItemEnum::Module(Module { |
| 87 | 89 | is_crate: true, |
| 88 | 90 | items: vec![Id(1)], |
| ... | ... | @@ -103,6 +105,7 @@ fn errors_on_local_in_paths_and_not_index() { |
| 103 | 105 | attrs: Vec::new(), |
| 104 | 106 | deprecation: None, |
| 105 | 107 | stability: None, |
| 108 | const_stability: None, | |
| 106 | 109 | inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }), |
| 107 | 110 | }, |
| 108 | 111 | ), |
| ... | ... | @@ -157,6 +160,7 @@ fn errors_on_missing_path() { |
| 157 | 160 | attrs: Vec::new(), |
| 158 | 161 | deprecation: None, |
| 159 | 162 | stability: None, |
| 163 | const_stability: None, | |
| 160 | 164 | inner: ItemEnum::Module(Module { |
| 161 | 165 | is_crate: true, |
| 162 | 166 | items: vec![Id(1), Id(2)], |
| ... | ... | @@ -177,6 +181,7 @@ fn errors_on_missing_path() { |
| 177 | 181 | attrs: Vec::new(), |
| 178 | 182 | deprecation: None, |
| 179 | 183 | stability: None, |
| 184 | const_stability: None, | |
| 180 | 185 | inner: ItemEnum::Struct(Struct { |
| 181 | 186 | kind: StructKind::Unit, |
| 182 | 187 | generics: generics.clone(), |
| ... | ... | @@ -197,6 +202,7 @@ fn errors_on_missing_path() { |
| 197 | 202 | attrs: Vec::new(), |
| 198 | 203 | deprecation: None, |
| 199 | 204 | stability: None, |
| 205 | const_stability: None, | |
| 200 | 206 | inner: ItemEnum::Function(Function { |
| 201 | 207 | sig: FunctionSignature { |
| 202 | 208 | inputs: vec![], |
| ... | ... | @@ -260,6 +266,7 @@ fn checks_local_crate_id_is_correct() { |
| 260 | 266 | attrs: Vec::new(), |
| 261 | 267 | deprecation: None, |
| 262 | 268 | stability: None, |
| 269 | const_stability: None, | |
| 263 | 270 | inner: ItemEnum::Module(Module { |
| 264 | 271 | is_crate: true, |
| 265 | 272 | items: vec![], |
tests/codegen-llvm/scalable-vectors/memcpy.rs created+88| ... | ... | @@ -0,0 +1,88 @@ |
| 1 | //@ compile-flags: -Copt-level=0 -Ctarget-feature=+sve,+sve2 | |
| 2 | //@ edition: 2021 | |
| 3 | //@ only-aarch64 | |
| 4 | ||
| 5 | #![crate_type = "lib"] | |
| 6 | #![feature(simd_ffi)] | |
| 7 | #![feature(stdarch_aarch64_sve)] | |
| 8 | ||
| 9 | // Test that `vscale * size` is generated for `memcpy` of scalable vector types | |
| 10 | ||
| 11 | use std::arch::aarch64::*; | |
| 12 | ||
| 13 | #[allow(improper_ctypes)] | |
| 14 | unsafe extern "C" { | |
| 15 | fn svcreate2_s16_wrapper(__dst: *mut svint16x2_t, x0: *const svint16_t, x1: *const svint16_t); | |
| 16 | fn svcreate3_s16_wrapper( | |
| 17 | __dst: *mut svint16x3_t, | |
| 18 | x0: *const svint16_t, | |
| 19 | x1: *const svint16_t, | |
| 20 | x2: *const svint16_t, | |
| 21 | ); | |
| 22 | fn svcreate4_s16_wrapper( | |
| 23 | __dst: *mut svint16x4_t, | |
| 24 | x0: *const svint16_t, | |
| 25 | x1: *const svint16_t, | |
| 26 | x2: *const svint16_t, | |
| 27 | x3: *const svint16_t, | |
| 28 | ); | |
| 29 | } | |
| 30 | ||
| 31 | pub fn foo(x0_val: svint16_t) { | |
| 32 | unsafe { | |
| 33 | let __pred = svptrue_b16(); | |
| 34 | ||
| 35 | let mut __c_return_value = std::mem::MaybeUninit::uninit(); | |
| 36 | svcreate2_s16_wrapper(__c_return_value.as_mut_ptr(), &raw const x0_val, &raw const x0_val); | |
| 37 | let __c_return_value = __c_return_value.assume_init(); | |
| 38 | // CHECK: call void @svcreate2_s16_wrapper( | |
| 39 | // CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() | |
| 40 | // CHECK-NEXT: [[VSCALE_SIZE:%.*]] = mul i64 [[VSCALE]], 32 | |
| 41 | // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64({{.*}}, {{.*}}, i64 [[VSCALE_SIZE]] | |
| 42 | ||
| 43 | let eq = svcmpeq_s16( | |
| 44 | __pred, | |
| 45 | svget2_s16::<1>(__c_return_value), | |
| 46 | svget2_s16::<1>(__c_return_value), | |
| 47 | ); | |
| 48 | ||
| 49 | let mut __c_return_value = std::mem::MaybeUninit::uninit(); | |
| 50 | svcreate3_s16_wrapper( | |
| 51 | __c_return_value.as_mut_ptr(), | |
| 52 | &raw const x0_val, | |
| 53 | &raw const x0_val, | |
| 54 | &raw const x0_val, | |
| 55 | ); | |
| 56 | let __c_return_value = __c_return_value.assume_init(); | |
| 57 | // CHECK: call void @svcreate3_s16_wrapper( | |
| 58 | // CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() | |
| 59 | // CHECK-NEXT: [[VSCALE_SIZE:%.*]] = mul i64 [[VSCALE]], 48 | |
| 60 | // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64({{.*}}, {{.*}}, i64 [[VSCALE_SIZE]] | |
| 61 | ||
| 62 | let eq = svcmpeq_s16( | |
| 63 | __pred, | |
| 64 | svget3_s16::<2>(__c_return_value), | |
| 65 | svget3_s16::<2>(__c_return_value), | |
| 66 | ); | |
| 67 | ||
| 68 | let mut __c_return_value = std::mem::MaybeUninit::uninit(); | |
| 69 | svcreate4_s16_wrapper( | |
| 70 | __c_return_value.as_mut_ptr(), | |
| 71 | &raw const x0_val, | |
| 72 | &raw const x0_val, | |
| 73 | &raw const x0_val, | |
| 74 | &raw const x0_val, | |
| 75 | ); | |
| 76 | let __c_return_value = __c_return_value.assume_init(); | |
| 77 | // CHECK: call void @svcreate4_s16_wrapper( | |
| 78 | // CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64() | |
| 79 | // CHECK-NEXT: [[VSCALE_SIZE:%.*]] = mul i64 [[VSCALE]], 64 | |
| 80 | // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64({{.*}}, {{.*}}, i64 [[VSCALE_SIZE]] | |
| 81 | ||
| 82 | let eq = svcmpeq_s16( | |
| 83 | __pred, | |
| 84 | svget4_s16::<3>(__c_return_value), | |
| 85 | svget4_s16::<3>(__c_return_value), | |
| 86 | ); | |
| 87 | } | |
| 88 | } |
tests/run-make/cdylib-export-c-library-symbols/rmake.rs+27-14| ... | ... | @@ -1,41 +1,54 @@ |
| 1 | 1 | //@ ignore-nvptx64 |
| 2 | 2 | //@ ignore-wasm |
| 3 | 3 | //@ ignore-cross-compile |
| 4 | // FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple. | |
| 5 | // Need to be resolved. | |
| 6 | //@ ignore-windows | |
| 7 | //@ ignore-apple | |
| 8 | 4 | // Reason: the compiled binary is executed |
| 9 | 5 | |
| 10 | 6 | use run_make_support::{ |
| 11 | build_native_static_lib, cc, dynamic_lib_name, is_aix, is_darwin, llvm_nm, rustc, | |
| 7 | build_native_static_lib, cc, dynamic_lib_name, is_aix, is_darwin, is_windows, is_windows_msvc, | |
| 8 | llvm_ar, llvm_nm, llvm_readobj, rfs, rustc, static_lib_name, | |
| 12 | 9 | }; |
| 13 | 10 | |
| 14 | 11 | fn main() { |
| 15 | cc().input("foo.c").arg("-c").out_exe("foo.o").run(); | |
| 16 | build_native_static_lib("foo"); | |
| 12 | let obj_file = if is_windows_msvc() { "foo.obj" } else { "foo.o" }; | |
| 13 | cc().input("foo.c").arg("-c").arg("-fno-lto").out_exe(obj_file).run(); | |
| 14 | llvm_ar().obj_to_ar().output_input(&static_lib_name("foo"), obj_file).run(); | |
| 17 | 15 | |
| 18 | 16 | rustc().input("foo.rs").arg("-lstatic=foo").crate_type("cdylib").run(); |
| 19 | 17 | |
| 20 | let out = llvm_nm() | |
| 21 | .input(dynamic_lib_name("foo")) | |
| 22 | .run() | |
| 23 | .assert_stdout_not_contains_regex("T *my_function"); | |
| 18 | if is_darwin() { | |
| 19 | llvm_nm().input(dynamic_lib_name("foo")).run().assert_stdout_not_contains("T _my_function"); | |
| 20 | } else if is_windows() { | |
| 21 | llvm_readobj() | |
| 22 | .arg("--coff-exports") | |
| 23 | .input(dynamic_lib_name("foo")) | |
| 24 | .run() | |
| 25 | .assert_stdout_not_contains("my_function"); | |
| 26 | } else { | |
| 27 | llvm_nm().input(dynamic_lib_name("foo")).run().assert_stdout_not_contains("T my_function"); | |
| 28 | } | |
| 29 | ||
| 30 | rfs::remove_file(dynamic_lib_name("foo")); | |
| 24 | 31 | |
| 25 | 32 | rustc().input("foo_export.rs").arg("-lstatic:+export-symbols=foo").crate_type("cdylib").run(); |
| 26 | 33 | |
| 27 | 34 | if is_darwin() { |
| 28 | let out = llvm_nm() | |
| 35 | llvm_nm() | |
| 29 | 36 | .input(dynamic_lib_name("foo_export")) |
| 30 | 37 | .run() |
| 31 | 38 | .assert_stdout_contains("T _my_function"); |
| 39 | } else if is_windows() { | |
| 40 | llvm_readobj() | |
| 41 | .arg("--coff-exports") | |
| 42 | .input(dynamic_lib_name("foo_export")) | |
| 43 | .run() | |
| 44 | .assert_stdout_contains("my_function"); | |
| 32 | 45 | } else if is_aix() { |
| 33 | let out = llvm_nm() | |
| 46 | llvm_nm() | |
| 34 | 47 | .input(dynamic_lib_name("foo_export")) |
| 35 | 48 | .run() |
| 36 | 49 | .assert_stdout_contains("T .my_function"); |
| 37 | 50 | } else { |
| 38 | let out = llvm_nm() | |
| 51 | llvm_nm() | |
| 39 | 52 | .input(dynamic_lib_name("foo_export")) |
| 40 | 53 | .run() |
| 41 | 54 | .assert_stdout_contains("T my_function"); |
tests/rustdoc-gui/setting-go-to-only-result.goml+44-2| ... | ... | @@ -33,16 +33,18 @@ assert-local-storage: {"rustdoc-go-to-only-result": "true"} |
| 33 | 33 | |
| 34 | 34 | go-to: "file://" + |DOC_PATH| + "/lib2/index.html" |
| 35 | 35 | // We enter it into the search. |
| 36 | click: "#search-button" | |
| 37 | wait-for: "#alternative-display .search-input" | |
| 36 | 38 | write-into: (".search-input", "HasALongTraitWithParams") |
| 37 | 39 | wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"} |
| 38 | assert-window-property: ({"location": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH) | |
| 40 | assert-window-property: ({"location"."pathname": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH) | |
| 39 | 41 | |
| 40 | 42 | // Regression test for <https://github.com/rust-lang/rust/issues/112676>. |
| 41 | 43 | // If "go-to-only-result" is enabled and you go back to history, it should not lead you back to the |
| 42 | 44 | // page result again automatically. |
| 43 | 45 | history-go-back: |
| 44 | 46 | wait-for-document-property: {"title": "lib2 - Rust"} |
| 45 | assert-window-property: ({"location": "/lib2/index.html"}, ENDS_WITH) | |
| 47 | assert-window-property: ({"location"."pathname": "/lib2/index.html"}, ENDS_WITH) | |
| 46 | 48 | |
| 47 | 49 | // We try again to see if it goes to the only result |
| 48 | 50 | go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams" |
| ... | ... | @@ -69,3 +71,43 @@ call-function: ("check-setting", { |
| 69 | 71 | "storage_value": "false", |
| 70 | 72 | "setting_attribute_value": "false", |
| 71 | 73 | }) |
| 74 | ||
| 75 | define-function: ( | |
| 76 | "search-multiple-results", | |
| 77 | [location], | |
| 78 | block { | |
| 79 | // We wait for the search to be done. | |
| 80 | wait-for: ".search-form" | |
| 81 | // We ensure the page didn't change. | |
| 82 | assert-window-property: {"location"."pathname": |location|} | |
| 83 | // We ensure that there is more than 0 results. | |
| 84 | wait-for-text: ("#search-tabs > button:nth-child(1) .count", "(2)", CONTAINS) | |
| 85 | wait-for-text: ("#search-tabs > button:nth-child(2) .count", "(1)", CONTAINS) | |
| 86 | wait-for-text: ("#search-tabs > button:nth-child(3) .count", "(0)", CONTAINS) | |
| 87 | }, | |
| 88 | ) | |
| 89 | ||
| 90 | // This is a regression test to ensure that it works when the setting is switched in-between. It | |
| 91 | // could be reproduced by: | |
| 92 | // 1. Doing a search (with "in parameters" or "in return types" having exactly one result) | |
| 93 | // 2. Enabling the setting to true. | |
| 94 | // 3. Reloading the page. | |
| 95 | ||
| 96 | // First we go to a different page. | |
| 97 | go-to: "file://" + |DOC_PATH| + "/lib2/index.html" | |
| 98 | ||
| 99 | // The setting should be disabled. | |
| 100 | assert-local-storage-false: {"rustdoc-go-to-only-result": "true"} | |
| 101 | store-window-property: {"location"."pathname": location} | |
| 102 | click: "#search-button" | |
| 103 | wait-for: "#alternative-display .search-input" | |
| 104 | write-into: (".search-input", "Whitespace") | |
| 105 | call-function: ("search-multiple-results", {"location": |location|}) | |
| 106 | ||
| 107 | // We now toggle the setting and reload the page. | |
| 108 | call-function: ("open-settings-menu", {}) | |
| 109 | click: "#go-to-only-result" | |
| 110 | assert-local-storage: {"rustdoc-go-to-only-result": "true"} | |
| 111 | ||
| 112 | reload: | |
| 113 | call-function: ("search-multiple-results", {"location": |location|}) |
tests/rustdoc-json/attrs/stability/const.rs created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | #![feature(staged_api)] | |
| 2 | ||
| 3 | //@ is "$.index[?(@.name=='non_const_function')].const_stability" null | |
| 4 | #[stable(feature = "non_const_function_feature", since = "0.9.0")] | |
| 5 | pub fn non_const_function() {} | |
| 6 | ||
| 7 | //@ set stable_const_fn = "$.index[?(@.name=='stable_const_fn')].id" | |
| 8 | //@ is "$.index[?(@.name=='stable_const_fn')].stability.level" '"stable"' | |
| 9 | //@ is "$.index[?(@.name=='stable_const_fn')].stability.feature" '"stable_const_fn_feature"' | |
| 10 | //@ is "$.index[?(@.name=='stable_const_fn')].stability.since" '"1.0.0"' | |
| 11 | //@ is "$.index[?(@.name=='stable_const_fn')].const_stability.level" '"stable"' | |
| 12 | //@ is "$.index[?(@.name=='stable_const_fn')].const_stability.feature" '"stable_const_fn_const_feature"' | |
| 13 | //@ is "$.index[?(@.name=='stable_const_fn')].const_stability.since" '"1.1.0"' | |
| 14 | //@ is "$.index[?(@.name=='stable_const_fn')].attrs" [] | |
| 15 | #[stable(feature = "stable_const_fn_feature", since = "1.0.0")] | |
| 16 | #[rustc_const_stable(feature = "stable_const_fn_const_feature", since = "1.1.0")] | |
| 17 | pub const fn stable_const_fn() {} | |
| 18 | ||
| 19 | //@ is "$.index[?(@.name=='const_unstable_fn')].stability.level" '"stable"' | |
| 20 | //@ is "$.index[?(@.name=='const_unstable_fn')].stability.feature" '"const_unstable_fn_feature"' | |
| 21 | //@ is "$.index[?(@.name=='const_unstable_fn')].stability.since" '"2.0.0"' | |
| 22 | //@ is "$.index[?(@.name=='const_unstable_fn')].const_stability.level" '"unstable"' | |
| 23 | //@ is "$.index[?(@.name=='const_unstable_fn')].const_stability.feature" '"const_unstable_fn_const_feature"' | |
| 24 | //@ !has "$.index[?(@.name=='const_unstable_fn')].const_stability.since" | |
| 25 | //@ is "$.index[?(@.name=='const_unstable_fn')].attrs" [] | |
| 26 | #[stable(feature = "const_unstable_fn_feature", since = "2.0.0")] | |
| 27 | #[rustc_const_unstable(feature = "const_unstable_fn_const_feature", issue = "none")] | |
| 28 | pub const fn const_unstable_fn() {} | |
| 29 | ||
| 30 | // Even when the item itself is unstable, if a separate const-stability attribute is present, | |
| 31 | // that's a distinct fact possibly associated with a different feature gate. | |
| 32 | // It should therefore be exposed on its own, instead of being collapsed into regular stability. | |
| 33 | //@ is "$.index[?(@.name=='unstable_fn_with_explicit_const_gate')].stability.level" '"unstable"' | |
| 34 | //@ is "$.index[?(@.name=='unstable_fn_with_explicit_const_gate')].stability.feature" '"unstable_fn_with_explicit_const_gate_feature"' | |
| 35 | //@ !has "$.index[?(@.name=='unstable_fn_with_explicit_const_gate')].stability.since" | |
| 36 | //@ is "$.index[?(@.name=='unstable_fn_with_explicit_const_gate')].const_stability.level" '"unstable"' | |
| 37 | //@ is "$.index[?(@.name=='unstable_fn_with_explicit_const_gate')].const_stability.feature" '"explicit_const_gate_on_unstable_fn"' | |
| 38 | //@ !has "$.index[?(@.name=='unstable_fn_with_explicit_const_gate')].const_stability.since" | |
| 39 | //@ is "$.index[?(@.name=='unstable_fn_with_explicit_const_gate')].attrs" [] | |
| 40 | #[unstable(feature = "unstable_fn_with_explicit_const_gate_feature", issue = "none")] | |
| 41 | #[rustc_const_unstable(feature = "explicit_const_gate_on_unstable_fn", issue = "none")] | |
| 42 | pub const fn unstable_fn_with_explicit_const_gate() {} | |
| 43 | ||
| 44 | // `lookup_const_stability` synthesizes a const-unstable record for this item from its regular | |
| 45 | // instability. Rustdoc JSON filters that out because there is no separate const feature gate. | |
| 46 | //@ is "$.index[?(@.name=='unstable_const_fn_without_const_gate')].stability.level" '"unstable"' | |
| 47 | //@ is "$.index[?(@.name=='unstable_const_fn_without_const_gate')].stability.feature" '"unstable_const_fn_without_const_gate_feature"' | |
| 48 | //@ is "$.index[?(@.name=='unstable_const_fn_without_const_gate')].const_stability" null | |
| 49 | #[unstable(feature = "unstable_const_fn_without_const_gate_feature", issue = "none")] | |
| 50 | pub const fn unstable_const_fn_without_const_gate() {} | |
| 51 | ||
| 52 | // The `Use` item describes the re-export. It doesn't have `const_stability` of its own. | |
| 53 | //@ is "$.index[?(@.inner.use.name=='stable_const_fn_reexport')].const_stability" null | |
| 54 | //@ is "$.index[?(@.inner.use.name=='stable_const_fn_reexport')].inner.use.id" $stable_const_fn | |
| 55 | pub use stable_const_fn as stable_const_fn_reexport; |
tests/rustdoc-json/attrs/stability/const_traits.rs created+159| ... | ... | @@ -0,0 +1,159 @@ |
| 1 | #![feature(staged_api, const_trait_impl)] | |
| 2 | ||
| 3 | #[stable(feature = "const_trait_target_feature", since = "1.0.0")] | |
| 4 | pub struct ConstTraitTarget; | |
| 5 | ||
| 6 | #[stable(feature = "const_stable_trait_target_feature", since = "1.0.0")] | |
| 7 | pub struct ConstStableTraitTarget; | |
| 8 | ||
| 9 | #[stable(feature = "inherent_const_method_target_feature", since = "1.1.0")] | |
| 10 | pub struct InherentConstMethodTarget; | |
| 11 | ||
| 12 | impl InherentConstMethodTarget { | |
| 13 | // This item is plain unstable, not const-unstable specifically. | |
| 14 | // Rustdoc JSON should populate `stability` only, not both it and `const_stability`. | |
| 15 | // Duplicating the info would just add noise to the JSON file. | |
| 16 | //@ is "$.index[?(@.name=='unstable_inherent_const_method_without_const_gate')].stability.level" '"unstable"' | |
| 17 | //@ is "$.index[?(@.name=='unstable_inherent_const_method_without_const_gate')].stability.feature" '"unstable_inherent_const_method_without_const_gate"' | |
| 18 | //@ is "$.index[?(@.name=='unstable_inherent_const_method_without_const_gate')].const_stability" null | |
| 19 | #[unstable(feature = "unstable_inherent_const_method_without_const_gate", issue = "none")] | |
| 20 | pub const fn unstable_inherent_const_method_without_const_gate(&self) {} | |
| 21 | } | |
| 22 | ||
| 23 | //@ is "$.index[?(@.name=='ConstTrait')].stability.level" '"stable"' | |
| 24 | //@ is "$.index[?(@.name=='ConstTrait')].stability.feature" '"const_trait_feature"' | |
| 25 | //@ is "$.index[?(@.name=='ConstTrait')].stability.since" '"2.0.0"' | |
| 26 | //@ is "$.index[?(@.name=='ConstTrait')].const_stability.level" '"unstable"' | |
| 27 | //@ is "$.index[?(@.name=='ConstTrait')].const_stability.feature" '"const_trait_const_feature"' | |
| 28 | //@ !has "$.index[?(@.name=='ConstTrait')].const_stability.since" | |
| 29 | //@ is "$.index[?(@.name=='ConstTrait')].attrs" [] | |
| 30 | #[stable(feature = "const_trait_feature", since = "2.0.0")] | |
| 31 | #[rustc_const_unstable(feature = "const_trait_const_feature", issue = "none")] | |
| 32 | pub const trait ConstTrait { | |
| 33 | // This item is *not* usable in a const context, because its parent is const-unstable. | |
| 34 | //@ is "$.index[?(@.docs=='assoc type inside const trait')].const_stability.level" '"unstable"' | |
| 35 | //@ is "$.index[?(@.docs=='assoc type inside const trait')].const_stability.feature" '"const_trait_const_feature"' | |
| 36 | //@ !has "$.index[?(@.docs=='assoc type inside const trait')].const_stability.since" | |
| 37 | /// assoc type inside const trait | |
| 38 | #[stable(feature = "trait_assoc_type_feature", since = "2.1.0")] | |
| 39 | type TraitAssocType; | |
| 40 | ||
| 41 | // This item is also *not* usable in a const context, because its parent is const-unstable. | |
| 42 | //@ is "$.index[?(@.docs=='method inside const trait')].const_stability.level" '"unstable"' | |
| 43 | //@ is "$.index[?(@.docs=='method inside const trait')].const_stability.feature" '"const_trait_const_feature"' | |
| 44 | //@ !has "$.index[?(@.docs=='method inside const trait')].const_stability.since" | |
| 45 | /// method inside const trait | |
| 46 | #[stable(feature = "trait_method_feature", since = "2.2.0")] | |
| 47 | fn trait_method(&self); | |
| 48 | ||
| 49 | // An associated const can't be const-unstable. | |
| 50 | // It is usable in a const context *regardless* of the fact its parent is const-unstable. | |
| 51 | // See the UI test in `tests/ui/traits/const-traits/associated-const-stability.rs` for proof. | |
| 52 | //@ is "$.index[?(@.docs=='assoc const inside const trait')].const_stability" null | |
| 53 | /// assoc const inside const trait | |
| 54 | #[stable(feature = "trait_assoc_const_feature", since = "2.3.0")] | |
| 55 | const TRAIT_ASSOC_CONST: usize; | |
| 56 | } | |
| 57 | ||
| 58 | //@ is "$.index[?(@.name=='ConstTraitWithUnstableMethod')].stability.level" '"stable"' | |
| 59 | //@ is "$.index[?(@.name=='ConstTraitWithUnstableMethod')].const_stability.level" '"unstable"' | |
| 60 | //@ is "$.index[?(@.name=='ConstTraitWithUnstableMethod')].const_stability.feature" '"const_trait_with_unstable_method_const_feature"' | |
| 61 | #[stable(feature = "const_trait_with_unstable_method_feature", since = "2.4.0")] | |
| 62 | #[rustc_const_unstable(feature = "const_trait_with_unstable_method_const_feature", issue = "none")] | |
| 63 | pub const trait ConstTraitWithUnstableMethod { | |
| 64 | // The method has its own regular instability, but no separate const-stability attribute. | |
| 65 | // Even if it became stable, the parent's const-instability would still dominate and | |
| 66 | // keep it const-unstable. Rustdoc JSON should expose the inherited const-instability. | |
| 67 | //@ is "$.index[?(@.name=='unstable_method_without_const_gate')].stability.level" '"unstable"' | |
| 68 | //@ is "$.index[?(@.name=='unstable_method_without_const_gate')].stability.feature" '"unstable_method_without_const_gate"' | |
| 69 | //@ is "$.index[?(@.name=='unstable_method_without_const_gate')].const_stability.level" '"unstable"' | |
| 70 | //@ is "$.index[?(@.name=='unstable_method_without_const_gate')].const_stability.feature" '"const_trait_with_unstable_method_const_feature"' | |
| 71 | #[unstable(feature = "unstable_method_without_const_gate", issue = "none")] | |
| 72 | fn unstable_method_without_const_gate(&self); | |
| 73 | } | |
| 74 | ||
| 75 | //@ is "$.index[?(@.docs=='const trait impl')].stability.level" '"stable"' | |
| 76 | //@ is "$.index[?(@.docs=='const trait impl')].stability.feature" '"const_trait_impl_feature"' | |
| 77 | //@ is "$.index[?(@.docs=='const trait impl')].stability.since" '"3.0.0"' | |
| 78 | //@ is "$.index[?(@.docs=='const trait impl')].const_stability.level" '"unstable"' | |
| 79 | //@ is "$.index[?(@.docs=='const trait impl')].const_stability.feature" '"const_trait_impl_const_feature"' | |
| 80 | //@ !has "$.index[?(@.docs=='const trait impl')].const_stability.since" | |
| 81 | /// const trait impl | |
| 82 | #[stable(feature = "const_trait_impl_feature", since = "3.0.0")] | |
| 83 | #[rustc_const_unstable(feature = "const_trait_impl_const_feature", issue = "none")] | |
| 84 | const impl ConstTrait for ConstTraitTarget { | |
| 85 | // This item is *not* usable in a const context, because its parent is const-unstable. | |
| 86 | //@ is "$.index[?(@.docs=='assoc type inside const trait impl')].const_stability.level" '"unstable"' | |
| 87 | //@ is "$.index[?(@.docs=='assoc type inside const trait impl')].const_stability.feature" '"const_trait_impl_const_feature"' | |
| 88 | //@ !has "$.index[?(@.docs=='assoc type inside const trait impl')].const_stability.since" | |
| 89 | /// assoc type inside const trait impl | |
| 90 | type TraitAssocType = usize; | |
| 91 | ||
| 92 | // This item is also *not* usable in a const context, because its parent is const-unstable. | |
| 93 | //@ is "$.index[?(@.docs=='method inside const trait impl')].const_stability.level" '"unstable"' | |
| 94 | //@ is "$.index[?(@.docs=='method inside const trait impl')].const_stability.feature" '"const_trait_impl_const_feature"' | |
| 95 | //@ !has "$.index[?(@.docs=='method inside const trait impl')].const_stability.since" | |
| 96 | /// method inside const trait impl | |
| 97 | fn trait_method(&self) {} | |
| 98 | ||
| 99 | // An associated const can't be const-unstable. | |
| 100 | // It is usable in a const context *regardless* of the fact its parent is const-unstable. | |
| 101 | // See the UI test in `tests/ui/traits/const-traits/associated-const-stability.rs` for proof. | |
| 102 | //@ is "$.index[?(@.docs=='assoc const inside const trait impl')].const_stability" null | |
| 103 | /// assoc const inside const trait impl | |
| 104 | const TRAIT_ASSOC_CONST: usize = 0; | |
| 105 | } | |
| 106 | ||
| 107 | // The `const trait` is const-stable. We indicate that *once* on the trait, but since | |
| 108 | // there are no special cases here (unlike in the const-unstable case with associated consts) | |
| 109 | // we do not duplicate the const-stability to all the associated items so as not to bloat the JSON. | |
| 110 | //@ is "$.index[?(@.name=='ConstStableTrait')].stability.level" '"stable"' | |
| 111 | //@ is "$.index[?(@.name=='ConstStableTrait')].stability.feature" '"const_stable_trait_feature"' | |
| 112 | //@ is "$.index[?(@.name=='ConstStableTrait')].stability.since" '"4.0.0"' | |
| 113 | //@ is "$.index[?(@.name=='ConstStableTrait')].const_stability.level" '"stable"' | |
| 114 | //@ is "$.index[?(@.name=='ConstStableTrait')].const_stability.since" '"4.0.0"' | |
| 115 | //@ is "$.index[?(@.name=='ConstStableTrait')].const_stability.feature" '"const_stable_trait_const_feature"' | |
| 116 | #[stable(feature = "const_stable_trait_feature", since = "4.0.0")] | |
| 117 | #[rustc_const_stable(feature = "const_stable_trait_const_feature", since = "4.0.0")] | |
| 118 | pub const trait ConstStableTrait { | |
| 119 | //@ is "$.index[?(@.docs=='assoc type inside const-stable trait')].const_stability" null | |
| 120 | /// assoc type inside const-stable trait | |
| 121 | #[stable(feature = "stable_trait_assoc_type_feature", since = "4.1.0")] | |
| 122 | type StableTraitAssocType; | |
| 123 | ||
| 124 | //@ is "$.index[?(@.docs=='method inside const-stable trait')].const_stability" null | |
| 125 | /// method inside const-stable trait | |
| 126 | #[stable(feature = "stable_trait_method_feature", since = "4.2.0")] | |
| 127 | fn stable_trait_method(&self); | |
| 128 | ||
| 129 | //@ is "$.index[?(@.docs=='assoc const inside const-stable trait')].const_stability" null | |
| 130 | /// assoc const inside const-stable trait | |
| 131 | #[stable(feature = "stable_trait_assoc_const_feature", since = "4.3.0")] | |
| 132 | const STABLE_TRAIT_ASSOC_CONST: usize; | |
| 133 | } | |
| 134 | ||
| 135 | // The `const impl` is const-stable. We indicate that *once* on the impl itself, but since | |
| 136 | // there are no special cases here (unlike in the const-unstable case with associated consts) | |
| 137 | // we do not duplicate the const-stability to all the associated items so as not to bloat the JSON. | |
| 138 | //@ is "$.index[?(@.docs=='const-stable trait impl')].stability.level" '"stable"' | |
| 139 | //@ is "$.index[?(@.docs=='const-stable trait impl')].stability.feature" '"const_stable_trait_impl_feature"' | |
| 140 | //@ is "$.index[?(@.docs=='const-stable trait impl')].stability.since" '"5.0.0"' | |
| 141 | //@ is "$.index[?(@.docs=='const-stable trait impl')].const_stability.level" '"stable"' | |
| 142 | //@ is "$.index[?(@.docs=='const-stable trait impl')].const_stability.since" '"5.0.0"' | |
| 143 | //@ is "$.index[?(@.docs=='const-stable trait impl')].const_stability.feature" '"const_stable_trait_impl_const_feature"' | |
| 144 | /// const-stable trait impl | |
| 145 | #[stable(feature = "const_stable_trait_impl_feature", since = "5.0.0")] | |
| 146 | #[rustc_const_stable(feature = "const_stable_trait_impl_const_feature", since = "5.0.0")] | |
| 147 | const impl ConstStableTrait for ConstStableTraitTarget { | |
| 148 | //@ is "$.index[?(@.docs=='assoc type inside const-stable trait impl')].const_stability" null | |
| 149 | /// assoc type inside const-stable trait impl | |
| 150 | type StableTraitAssocType = usize; | |
| 151 | ||
| 152 | //@ is "$.index[?(@.docs=='method inside const-stable trait impl')].const_stability" null | |
| 153 | /// method inside const-stable trait impl | |
| 154 | fn stable_trait_method(&self) {} | |
| 155 | ||
| 156 | //@ is "$.index[?(@.docs=='assoc const inside const-stable trait impl')].const_stability" null | |
| 157 | /// assoc const inside const-stable trait impl | |
| 158 | const STABLE_TRAIT_ASSOC_CONST: usize = 1; | |
| 159 | } |
tests/rustdoc-ui/ice-bug-report-url.rs+1-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | |
| 5 | 5 | //@ normalize-stderr: "note: compiler flags.*\n\n" -> "" |
| 6 | 6 | //@ normalize-stderr: "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}" |
| 7 | //@ normalize-stderr: "thread.*panicked at compiler.*" -> "" | |
| 7 | //@ normalize-stderr: "thread 'rustc'.*panicked.*:\n.*\n" -> "" | |
| 8 | 8 | //@ normalize-stderr: " +\d{1,}: .*\n" -> "" |
| 9 | 9 | //@ normalize-stderr: " + at .*\n" -> "" |
| 10 | 10 | //@ normalize-stderr: ".*note: Some details are omitted.*\n" -> "" |
tests/rustdoc-ui/ice-bug-report-url.stderr-2| ... | ... | @@ -5,8 +5,6 @@ LL | fn wrong() |
| 5 | 5 | | ^ expected one of `->`, `where`, or `{` |
| 6 | 6 | |
| 7 | 7 | |
| 8 | ||
| 9 | aborting due to `-Z treat-err-as-bug=1` | |
| 10 | 8 | stack backtrace: |
| 11 | 9 | |
| 12 | 10 | error: the compiler unexpectedly panicked. This is a bug |
tests/rustdoc-ui/synthetic-auto-trait-impls/const-trait-bound.rs created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | // We used to ICE here while trying to synthesize auto trait impls. | |
| 2 | //@ check-pass | |
| 3 | ||
| 4 | #![feature(const_default)] | |
| 5 | #![feature(const_trait_impl)] | |
| 6 | ||
| 7 | pub struct Inner<T>(T); | |
| 8 | ||
| 9 | pub struct Outer<T>(Inner<T>); | |
| 10 | ||
| 11 | impl<T> Unpin for Inner<T> | |
| 12 | where | |
| 13 | T: const std::default::Default, | |
| 14 | {} |
tests/ui/abi/extern/extern-c-method-return-struct.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/26997>. | |
| 2 | //@ build-pass | |
| 3 | ||
| 4 | #![allow(dead_code)] | |
| 5 | pub struct Foo { | |
| 6 | x: isize, | |
| 7 | y: isize | |
| 8 | } | |
| 9 | ||
| 10 | impl Foo { | |
| 11 | #[allow(improper_ctypes_definitions)] | |
| 12 | pub extern "C" fn foo_new() -> Foo { | |
| 13 | Foo { x: 21, y: 33 } | |
| 14 | } | |
| 15 | } | |
| 16 | ||
| 17 | fn main() {} |
tests/ui/async-await/higher-ranked-auto-trait-18.no_assumptions.stderr created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | error: higher-ranked lifetime error | |
| 2 | --> $DIR/higher-ranked-auto-trait-18.rs:69:5 | |
| 3 | | | |
| 4 | LL | / require_send(async { | |
| 5 | LL | | let r = Receiver::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData }; | |
| 6 | LL | | let _ = r.await; | |
| 7 | LL | | }); | |
| 8 | | |______^ | |
| 9 | | | |
| 10 | = note: could not prove `{async block@$DIR/higher-ranked-auto-trait-18.rs:69:18: 69:23}: Send` | |
| 11 | ||
| 12 | error: aborting due to 1 previous error | |
| 13 |
tests/ui/async-await/higher-ranked-auto-trait-18.rs created+79| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | // Repro for a bug where `PhantomData<*mut ()>` + `unsafe impl Send` fails to prove | |
| 2 | // `Send` for an async block when the type parameter is a trait object (`dyn Trait`). | |
| 3 | // | |
| 4 | // The static assertion `assert_send::<Receiver<Box<dyn MyTrait>>>()` succeeds, | |
| 5 | // but the same type captured across an `.await` in an async block does not. | |
| 6 | // This is because MIR erases the `'static` lifetime from `dyn MyTrait + 'static`, | |
| 7 | // and the auto-trait analysis cannot recover the `T: 'static` bound without | |
| 8 | // higher-ranked assumptions. | |
| 9 | // | |
| 10 | // Using `PhantomData<Cell<()>>` instead of `PhantomData<*mut ()>` avoids the | |
| 11 | // issue because `Cell<()>` is natively `Send`, so no `unsafe impl` (with its | |
| 12 | // `T: 'static` bound) is needed. | |
| 13 | // | |
| 14 | // See <https://github.com/rust-lang/rust/issues/110338>. | |
| 15 | //@ edition: 2021 | |
| 16 | //@ revisions: assumptions no_assumptions | |
| 17 | //@[assumptions] compile-flags: -Zhigher-ranked-assumptions | |
| 18 | //@[assumptions] check-pass | |
| 19 | //@[no_assumptions] known-bug: #110338 | |
| 20 | ||
| 21 | use std::cell::Cell; | |
| 22 | use std::future::Future; | |
| 23 | use std::marker::PhantomData; | |
| 24 | use std::pin::Pin; | |
| 25 | use std::task::{Context, Poll}; | |
| 26 | ||
| 27 | // --- PhantomData<*mut ()> version: needs `unsafe impl Send` --- | |
| 28 | ||
| 29 | struct Receiver<T: Send + 'static> { | |
| 30 | _value: Option<T>, | |
| 31 | _not_sync: PhantomData<*mut ()>, | |
| 32 | } | |
| 33 | ||
| 34 | unsafe impl<T: Send + 'static> Send for Receiver<T> {} | |
| 35 | ||
| 36 | impl<T: Send + 'static> Future for Receiver<T> { | |
| 37 | type Output = T; | |
| 38 | fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { | |
| 39 | Poll::Pending | |
| 40 | } | |
| 41 | } | |
| 42 | ||
| 43 | // --- PhantomData<Cell<()>> version: auto-derived Send works --- | |
| 44 | ||
| 45 | struct ReceiverCell<T: Send + 'static> { | |
| 46 | _value: Option<T>, | |
| 47 | _not_sync: PhantomData<Cell<()>>, | |
| 48 | } | |
| 49 | ||
| 50 | impl<T: Send + 'static> Future for ReceiverCell<T> { | |
| 51 | type Output = T; | |
| 52 | fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { | |
| 53 | Poll::Pending | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | trait MyTrait: Send {} | |
| 58 | ||
| 59 | fn require_send<F: Future + Send>(_f: F) {} | |
| 60 | ||
| 61 | fn main() { | |
| 62 | // PhantomData<*mut ()> + concrete type: always works. | |
| 63 | require_send(async { | |
| 64 | let r = Receiver::<u32> { _value: None, _not_sync: PhantomData }; | |
| 65 | let _ = r.await; | |
| 66 | }); | |
| 67 | ||
| 68 | // PhantomData<*mut ()> + dyn Trait: fails without higher-ranked assumptions. | |
| 69 | require_send(async { | |
| 70 | let r = Receiver::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData }; | |
| 71 | let _ = r.await; | |
| 72 | }); | |
| 73 | ||
| 74 | // PhantomData<Cell<()>> + dyn Trait: always works (auto-derived Send). | |
| 75 | require_send(async { | |
| 76 | let r = ReceiverCell::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData }; | |
| 77 | let _ = r.await; | |
| 78 | }); | |
| 79 | } |
tests/ui/binop/binop-mutate-lhs-in-rhs.rs created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/27054>. | |
| 2 | //@ run-pass | |
| 3 | ||
| 4 | fn main() { | |
| 5 | let x = &mut 1; | |
| 6 | assert_eq!(*x + { *x=2; 1 }, 2); | |
| 7 | } |
tests/ui/coercion/infer-coerce-unsized-trait-object.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/27105>. | |
| 2 | //@ check-pass | |
| 3 | ||
| 4 | use std::cell::RefCell; | |
| 5 | use std::rc::Rc; | |
| 6 | ||
| 7 | pub struct Callbacks { | |
| 8 | callbacks: Vec<Rc<RefCell<dyn FnMut(i32)>>>, | |
| 9 | } | |
| 10 | ||
| 11 | impl Callbacks { | |
| 12 | pub fn register<F: FnMut(i32)+'static>(&mut self, callback: F) { | |
| 13 | self.callbacks.push(Rc::new(RefCell::new(callback))); | |
| 14 | } | |
| 15 | } | |
| 16 | ||
| 17 | fn main() {} |
tests/ui/drop/dst-coerce-unsized-drop.rs created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/26709>. | |
| 2 | //! Test value is still getting dropped after unsized coerce. | |
| 3 | //! | |
| 4 | //! Fat pointer was passed in two immediate args, but the drop invocation | |
| 5 | //! used to accept one, which led to ICE. | |
| 6 | //@ run-pass | |
| 7 | ||
| 8 | struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(dead_code)] T); | |
| 9 | ||
| 10 | impl<'a, T: ?Sized> Drop for Wrapper<'a, T> { | |
| 11 | fn drop(&mut self) { | |
| 12 | *self.0 = 432; | |
| 13 | } | |
| 14 | } | |
| 15 | ||
| 16 | fn main() { | |
| 17 | let mut x = 0; | |
| 18 | { | |
| 19 | let wrapper = Box::new(Wrapper(&mut x, 123)); | |
| 20 | let _: Box<Wrapper<dyn Send>> = wrapper; | |
| 21 | } | |
| 22 | assert_eq!(432, x) | |
| 23 | } |
tests/ui/drop/enum-destructor-on-unwind.rs created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/26655>. | |
| 2 | //! Check that the destructors of simple enums are run on unwinding. | |
| 3 | //@ run-pass | |
| 4 | //@ needs-unwind | |
| 5 | //@ needs-threads | |
| 6 | //@ ignore-backends: gcc | |
| 7 | ||
| 8 | use std::sync::atomic::{Ordering, AtomicUsize}; | |
| 9 | use std::thread; | |
| 10 | ||
| 11 | static LOG: AtomicUsize = AtomicUsize::new(0); | |
| 12 | ||
| 13 | enum WithDtor { Val } | |
| 14 | impl Drop for WithDtor { | |
| 15 | fn drop(&mut self) { | |
| 16 | LOG.store(LOG.load(Ordering::SeqCst)+1,Ordering::SeqCst); | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | pub fn main() { | |
| 21 | thread::spawn(move|| { | |
| 22 | let _e: WithDtor = WithDtor::Val; | |
| 23 | panic!("fail"); | |
| 24 | }).join().unwrap_err(); | |
| 25 | ||
| 26 | assert_eq!(LOG.load(Ordering::SeqCst), 1); | |
| 27 | } |
tests/ui/explicit-tail-calls/unsupported-abi/rust-call.rs created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | // extern "rust-call" untuples the first (and only, except self) argument, this requires additional | |
| 2 | // support for tail calls to work correctly. Since there doesn't seem to be a usecase for tail | |
| 3 | // calling extern "rust-call" functions (extern "rust-call" only shows up in closures, which we | |
| 4 | // disallow tail-calling anyway), we just disallow that. | |
| 5 | // | |
| 6 | // @ ignore-backends: gcc | |
| 7 | #![expect(incomplete_features)] | |
| 8 | #![feature(explicit_tail_calls)] | |
| 9 | #![feature(unboxed_closures)] | |
| 10 | ||
| 11 | extern "rust-call" fn a(_: ()) { | |
| 12 | become a(()); | |
| 13 | //~^ error: ABI does not support guaranteed tail calls | |
| 14 | } | |
| 15 | ||
| 16 | fn main() {} |
tests/ui/explicit-tail-calls/unsupported-abi/rust-call.stderr created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | error: ABI does not support guaranteed tail calls | |
| 2 | --> $DIR/rust-call.rs:12:5 | |
| 3 | | | |
| 4 | LL | become a(()); | |
| 5 | | ^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: `become` is not supported for `extern "rust-call"` functions | |
| 8 | ||
| 9 | error: aborting due to 1 previous error | |
| 10 |
tests/ui/functional-struct-update/fru-on-enum-variant.rs created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/26948>. | |
| 2 | ||
| 3 | fn main() { | |
| 4 | enum Foo { A { x: u32 } } | |
| 5 | let orig = Foo::A { x: 5 }; | |
| 6 | Foo::A { x: 6, ..orig }; | |
| 7 | //~^ ERROR functional record update syntax requires a struct | |
| 8 | } |
tests/ui/functional-struct-update/fru-on-enum-variant.stderr created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | error[E0436]: functional record update syntax requires a struct | |
| 2 | --> $DIR/fru-on-enum-variant.rs:6:22 | |
| 3 | | | |
| 4 | LL | Foo::A { x: 6, ..orig }; | |
| 5 | | ^^^^ | |
| 6 | ||
| 7 | error: aborting due to 1 previous error | |
| 8 | ||
| 9 | For more information about this error, try `rustc --explain E0436`. |
tests/ui/issues/issue-26655.rs deleted-27| ... | ... | @@ -1,27 +0,0 @@ |
| 1 | //@ run-pass | |
| 2 | //@ needs-unwind | |
| 3 | //@ needs-threads | |
| 4 | //@ ignore-backends: gcc | |
| 5 | ||
| 6 | // Check that the destructors of simple enums are run on unwinding | |
| 7 | ||
| 8 | use std::sync::atomic::{Ordering, AtomicUsize}; | |
| 9 | use std::thread; | |
| 10 | ||
| 11 | static LOG: AtomicUsize = AtomicUsize::new(0); | |
| 12 | ||
| 13 | enum WithDtor { Val } | |
| 14 | impl Drop for WithDtor { | |
| 15 | fn drop(&mut self) { | |
| 16 | LOG.store(LOG.load(Ordering::SeqCst)+1,Ordering::SeqCst); | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | pub fn main() { | |
| 21 | thread::spawn(move|| { | |
| 22 | let _e: WithDtor = WithDtor::Val; | |
| 23 | panic!("fail"); | |
| 24 | }).join().unwrap_err(); | |
| 25 | ||
| 26 | assert_eq!(LOG.load(Ordering::SeqCst), 1); | |
| 27 | } |
tests/ui/issues/issue-26709.rs deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | //@ run-pass | |
| 2 | struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(dead_code)] T); | |
| 3 | ||
| 4 | impl<'a, T: ?Sized> Drop for Wrapper<'a, T> { | |
| 5 | fn drop(&mut self) { | |
| 6 | *self.0 = 432; | |
| 7 | } | |
| 8 | } | |
| 9 | ||
| 10 | fn main() { | |
| 11 | let mut x = 0; | |
| 12 | { | |
| 13 | let wrapper = Box::new(Wrapper(&mut x, 123)); | |
| 14 | let _: Box<Wrapper<dyn Send>> = wrapper; | |
| 15 | } | |
| 16 | assert_eq!(432, x) | |
| 17 | } |
tests/ui/issues/issue-26802.rs deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | //@ run-pass | |
| 2 | trait Foo<'a> { | |
| 3 | fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 } | |
| 4 | } | |
| 5 | ||
| 6 | pub struct FooBar; | |
| 7 | impl Foo<'static> for FooBar {} | |
| 8 | fn test(foobar: FooBar) -> Box<dyn Foo<'static>> { | |
| 9 | Box::new(foobar) | |
| 10 | } | |
| 11 | ||
| 12 | fn main() { | |
| 13 | assert_eq!(test(FooBar).bar(&4), 11); | |
| 14 | } |
tests/ui/issues/issue-26805.rs deleted-6| ... | ... | @@ -1,6 +0,0 @@ |
| 1 | //@ run-pass | |
| 2 | struct NonOrd; | |
| 3 | ||
| 4 | fn main() { | |
| 5 | let _: Box<dyn Iterator<Item = _>> = Box::new(vec![NonOrd].into_iter()); | |
| 6 | } |
tests/ui/issues/issue-26948.rs deleted-6| ... | ... | @@ -1,6 +0,0 @@ |
| 1 | fn main() { | |
| 2 | enum Foo { A { x: u32 } } | |
| 3 | let orig = Foo::A { x: 5 }; | |
| 4 | Foo::A { x: 6, ..orig }; | |
| 5 | //~^ ERROR functional record update syntax requires a struct | |
| 6 | } |
tests/ui/issues/issue-26948.stderr deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | error[E0436]: functional record update syntax requires a struct | |
| 2 | --> $DIR/issue-26948.rs:4:22 | |
| 3 | | | |
| 4 | LL | Foo::A { x: 6, ..orig }; | |
| 5 | | ^^^^ | |
| 6 | ||
| 7 | error: aborting due to 1 previous error | |
| 8 | ||
| 9 | For more information about this error, try `rustc --explain E0436`. |
tests/ui/issues/issue-26997.rs deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | //@ build-pass | |
| 2 | #![allow(dead_code)] | |
| 3 | pub struct Foo { | |
| 4 | x: isize, | |
| 5 | y: isize | |
| 6 | } | |
| 7 | ||
| 8 | impl Foo { | |
| 9 | #[allow(improper_ctypes_definitions)] | |
| 10 | pub extern "C" fn foo_new() -> Foo { | |
| 11 | Foo { x: 21, y: 33 } | |
| 12 | } | |
| 13 | } | |
| 14 | ||
| 15 | fn main() {} |
tests/ui/issues/issue-27042.rs deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | // Regression test for #27042. Test that a loop's label is included in its span. | |
| 2 | ||
| 3 | fn main() { | |
| 4 | let _: i32 = | |
| 5 | 'a: // in this case, the citation is just the `break`: | |
| 6 | loop { break }; //~ ERROR mismatched types | |
| 7 | let _: i32 = | |
| 8 | 'b: //~ ERROR mismatched types | |
| 9 | //~^ WARN denote infinite loops with | |
| 10 | while true { break }; // but here we cite the whole loop | |
| 11 | let _: i32 = | |
| 12 | 'c: //~ ERROR mismatched types | |
| 13 | for _ in None { break }; // but here we cite the whole loop | |
| 14 | let _: i32 = | |
| 15 | 'd: //~ ERROR mismatched types | |
| 16 | while let Some(_) = None { break }; | |
| 17 | } |
tests/ui/issues/issue-27042.stderr deleted-57| ... | ... | @@ -1,57 +0,0 @@ |
| 1 | warning: denote infinite loops with `loop { ... }` | |
| 2 | --> $DIR/issue-27042.rs:8:9 | |
| 3 | | | |
| 4 | LL | / 'b: | |
| 5 | LL | | | |
| 6 | LL | | while true { break }; // but here we cite the whole loop | |
| 7 | | |__________________^ help: use `loop` | |
| 8 | | | |
| 9 | = note: `#[warn(while_true)]` on by default | |
| 10 | ||
| 11 | error[E0308]: mismatched types | |
| 12 | --> $DIR/issue-27042.rs:6:16 | |
| 13 | | | |
| 14 | LL | let _: i32 = | |
| 15 | | - expected because of this assignment | |
| 16 | LL | 'a: // in this case, the citation is just the `break`: | |
| 17 | LL | loop { break }; | |
| 18 | | ---- ^^^^^ expected `i32`, found `()` | |
| 19 | | | | |
| 20 | | this loop is expected to be of type `i32` | |
| 21 | | | |
| 22 | help: give the `break` a value of the expected type | |
| 23 | | | |
| 24 | LL | loop { break 42 }; | |
| 25 | | ++ | |
| 26 | ||
| 27 | error[E0308]: mismatched types | |
| 28 | --> $DIR/issue-27042.rs:8:9 | |
| 29 | | | |
| 30 | LL | let _: i32 = | |
| 31 | | --- expected due to this | |
| 32 | LL | / 'b: | |
| 33 | LL | | | |
| 34 | LL | | while true { break }; // but here we cite the whole loop | |
| 35 | | |____________________________^ expected `i32`, found `()` | |
| 36 | ||
| 37 | error[E0308]: mismatched types | |
| 38 | --> $DIR/issue-27042.rs:12:9 | |
| 39 | | | |
| 40 | LL | / 'c: | |
| 41 | LL | | for _ in None { break }; // but here we cite the whole loop | |
| 42 | | |_______________________________^ expected `i32`, found `()` | |
| 43 | | | |
| 44 | = note: `for` loops evaluate to unit type `()` | |
| 45 | ||
| 46 | error[E0308]: mismatched types | |
| 47 | --> $DIR/issue-27042.rs:15:9 | |
| 48 | | | |
| 49 | LL | let _: i32 = | |
| 50 | | --- expected due to this | |
| 51 | LL | / 'd: | |
| 52 | LL | | while let Some(_) = None { break }; | |
| 53 | | |__________________________________________^ expected `i32`, found `()` | |
| 54 | ||
| 55 | error: aborting due to 4 previous errors; 1 warning emitted | |
| 56 | ||
| 57 | For more information about this error, try `rustc --explain E0308`. |
tests/ui/issues/issue-27054-primitive-binary-ops.rs deleted-5| ... | ... | @@ -1,5 +0,0 @@ |
| 1 | //@ run-pass | |
| 2 | fn main() { | |
| 3 | let x = &mut 1; | |
| 4 | assert_eq!(*x + { *x=2; 1 }, 2); | |
| 5 | } |
tests/ui/issues/issue-27078.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | trait Foo { | |
| 2 | const BAR: i32; | |
| 3 | fn foo(self) -> &'static i32 { | |
| 4 | //~^ ERROR the size for values of type | |
| 5 | &<Self>::BAR | |
| 6 | } | |
| 7 | } | |
| 8 | ||
| 9 | fn main() {} |
tests/ui/issues/issue-27078.stderr deleted-19| ... | ... | @@ -1,19 +0,0 @@ |
| 1 | error[E0277]: the size for values of type `Self` cannot be known at compilation time | |
| 2 | --> $DIR/issue-27078.rs:3:12 | |
| 3 | | | |
| 4 | LL | fn foo(self) -> &'static i32 { | |
| 5 | | ^^^^ doesn't have a size known at compile-time | |
| 6 | | | |
| 7 | = help: unsized fn params are gated as an unstable feature | |
| 8 | help: consider further restricting `Self` | |
| 9 | | | |
| 10 | LL | fn foo(self) -> &'static i32 where Self: Sized { | |
| 11 | | +++++++++++++++++ | |
| 12 | help: function arguments must have a statically known size, borrowed types always have a known size | |
| 13 | | | |
| 14 | LL | fn foo(&self) -> &'static i32 { | |
| 15 | | + | |
| 16 | ||
| 17 | error: aborting due to 1 previous error | |
| 18 | ||
| 19 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/issues/issue-27105.rs deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | //@ check-pass | |
| 2 | use std::cell::RefCell; | |
| 3 | use std::rc::Rc; | |
| 4 | ||
| 5 | pub struct Callbacks { | |
| 6 | callbacks: Vec<Rc<RefCell<dyn FnMut(i32)>>>, | |
| 7 | } | |
| 8 | ||
| 9 | impl Callbacks { | |
| 10 | pub fn register<F: FnMut(i32)+'static>(&mut self, callback: F) { | |
| 11 | self.callbacks.push(Rc::new(RefCell::new(callback))); | |
| 12 | } | |
| 13 | } | |
| 14 | ||
| 15 | fn main() {} |
tests/ui/label/loop-label-included-in-span.rs created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/27042>. | |
| 2 | //! Test that a loop's label is included in its span. | |
| 3 | ||
| 4 | fn main() { | |
| 5 | let _: i32 = | |
| 6 | 'a: // in this case, the citation is just the `break`: | |
| 7 | loop { break }; //~ ERROR mismatched types | |
| 8 | let _: i32 = | |
| 9 | 'b: //~ ERROR mismatched types | |
| 10 | //~^ WARN denote infinite loops with | |
| 11 | while true { break }; // but here we cite the whole loop | |
| 12 | let _: i32 = | |
| 13 | 'c: //~ ERROR mismatched types | |
| 14 | for _ in None { break }; // but here we cite the whole loop | |
| 15 | let _: i32 = | |
| 16 | 'd: //~ ERROR mismatched types | |
| 17 | while let Some(_) = None { break }; | |
| 18 | } |
tests/ui/label/loop-label-included-in-span.stderr created+57| ... | ... | @@ -0,0 +1,57 @@ |
| 1 | warning: denote infinite loops with `loop { ... }` | |
| 2 | --> $DIR/loop-label-included-in-span.rs:9:9 | |
| 3 | | | |
| 4 | LL | / 'b: | |
| 5 | LL | | | |
| 6 | LL | | while true { break }; // but here we cite the whole loop | |
| 7 | | |__________________^ help: use `loop` | |
| 8 | | | |
| 9 | = note: `#[warn(while_true)]` on by default | |
| 10 | ||
| 11 | error[E0308]: mismatched types | |
| 12 | --> $DIR/loop-label-included-in-span.rs:7:16 | |
| 13 | | | |
| 14 | LL | let _: i32 = | |
| 15 | | - expected because of this assignment | |
| 16 | LL | 'a: // in this case, the citation is just the `break`: | |
| 17 | LL | loop { break }; | |
| 18 | | ---- ^^^^^ expected `i32`, found `()` | |
| 19 | | | | |
| 20 | | this loop is expected to be of type `i32` | |
| 21 | | | |
| 22 | help: give the `break` a value of the expected type | |
| 23 | | | |
| 24 | LL | loop { break 42 }; | |
| 25 | | ++ | |
| 26 | ||
| 27 | error[E0308]: mismatched types | |
| 28 | --> $DIR/loop-label-included-in-span.rs:9:9 | |
| 29 | | | |
| 30 | LL | let _: i32 = | |
| 31 | | --- expected due to this | |
| 32 | LL | / 'b: | |
| 33 | LL | | | |
| 34 | LL | | while true { break }; // but here we cite the whole loop | |
| 35 | | |____________________________^ expected `i32`, found `()` | |
| 36 | ||
| 37 | error[E0308]: mismatched types | |
| 38 | --> $DIR/loop-label-included-in-span.rs:13:9 | |
| 39 | | | |
| 40 | LL | / 'c: | |
| 41 | LL | | for _ in None { break }; // but here we cite the whole loop | |
| 42 | | |_______________________________^ expected `i32`, found `()` | |
| 43 | | | |
| 44 | = note: `for` loops evaluate to unit type `()` | |
| 45 | ||
| 46 | error[E0308]: mismatched types | |
| 47 | --> $DIR/loop-label-included-in-span.rs:16:9 | |
| 48 | | | |
| 49 | LL | let _: i32 = | |
| 50 | | --- expected due to this | |
| 51 | LL | / 'd: | |
| 52 | LL | | while let Some(_) = None { break }; | |
| 53 | | |__________________________________________^ expected `i32`, found `()` | |
| 54 | ||
| 55 | error: aborting due to 4 previous errors; 1 warning emitted | |
| 56 | ||
| 57 | For more information about this error, try `rustc --explain E0308`. |
tests/ui/panics/abort-on-panic.rs+9| ... | ... | @@ -61,11 +61,20 @@ fn test_always_abort_thread() { |
| 61 | 61 | bomb_out_but_not_abort("joined - but we were supposed to panic!"); |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | fn test_always_abort_resume_unwind() { | |
| 65 | panic::always_abort(); | |
| 66 | let _ = panic::catch_unwind(|| { | |
| 67 | panic::resume_unwind(Box::new(())); | |
| 68 | }); | |
| 69 | should_have_aborted(); | |
| 70 | } | |
| 71 | ||
| 64 | 72 | fn main() { |
| 65 | 73 | let tests: &[(_, fn())] = &[ |
| 66 | 74 | ("test", test), |
| 67 | 75 | ("test_always_abort", test_always_abort), |
| 68 | 76 | ("test_always_abort_thread", test_always_abort_thread), |
| 77 | ("test_always_abort_resume_unwind", test_always_abort_resume_unwind), | |
| 69 | 78 | ]; |
| 70 | 79 | |
| 71 | 80 | let args: Vec<String> = env::args().collect(); |
tests/ui/panics/panic-in-hook.rs created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | // Checks what happens when panicking inside the panic hook. | |
| 2 | ||
| 3 | //@ run-crash | |
| 4 | //@ exec-env:RUST_BACKTRACE=0 | |
| 5 | //@ check-run-results | |
| 6 | //@ error-pattern: panicked while processing panic | |
| 7 | //@ ignore-emscripten "RuntimeError" junk in output | |
| 8 | ||
| 9 | use std::panic; | |
| 10 | ||
| 11 | fn main() { | |
| 12 | panic::set_hook(Box::new(|_| panic!("panic in hook"))); | |
| 13 | panic!(); | |
| 14 | } |
tests/ui/panics/panic-in-hook.run.stderr created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | panicked at $DIR/panic-in-hook.rs:12:34: | |
| 2 | ||
| 3 | thread panicked while processing panic. aborting. |
tests/ui/panics/panic-resume_unwind-in-hook.rs created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | // Checks what happens when panicking inside the panic hook. | |
| 2 | ||
| 3 | //@ run-crash | |
| 4 | //@ exec-env:RUST_BACKTRACE=0 | |
| 5 | //@ check-run-results | |
| 6 | //@ error-pattern: panicked while processing panic | |
| 7 | //@ ignore-emscripten "RuntimeError" junk in output | |
| 8 | ||
| 9 | use std::panic; | |
| 10 | ||
| 11 | fn main() { | |
| 12 | panic::set_hook(Box::new(|_| panic::resume_unwind(Box::new(())))); | |
| 13 | panic!(); | |
| 14 | } |
tests/ui/panics/panic-resume_unwind-in-hook.run.stderr created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | thread panicked while processing panic. aborting. |
tests/ui/traits/const-traits/associated-const-stability.rs created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | //@ check-pass | |
| 2 | //@ aux-build: associated-const-stability.rs | |
| 3 | ||
| 4 | extern crate associated_const_stability; | |
| 5 | ||
| 6 | use associated_const_stability::{Probe, TraitWithConstGate}; | |
| 7 | ||
| 8 | // Demonstrate that it's possible to use a `const` associated item in a stable `const` context | |
| 9 | // even when the item is defined inside a const-unstable enclosing parent item. | |
| 10 | // | |
| 11 | // Here `TraitWithConstGate` is const-unstable, as is its `const impl` for `Probe`. | |
| 12 | // This crate *does not* enable the `const_trait_gate` feature for those const impls. | |
| 13 | // By showing that this crate compiles without that feature, while having const contexts | |
| 14 | // that use both `<Probe as TraitWithConstGate>::ASSOC` specifically | |
| 15 | // and generic `<T as TraitWithConstGate>::ASSOC`, we prove that the associated consts respect | |
| 16 | // the item-level stability like `#[stable]`, not const-stability like `#[rustc_const_unstable]`. | |
| 17 | ||
| 18 | const VALUE: usize = <Probe as TraitWithConstGate>::ASSOC; | |
| 19 | ||
| 20 | const fn example<T: TraitWithConstGate>(_: &T) -> usize { | |
| 21 | <T as TraitWithConstGate>::ASSOC | |
| 22 | } | |
| 23 | ||
| 24 | fn main() {} |
tests/ui/traits/const-traits/auxiliary/associated-const-stability.rs created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | #![feature(const_trait_impl)] | |
| 2 | #![feature(staged_api)] | |
| 3 | #![stable(feature = "rust1", since = "1.0.0")] | |
| 4 | ||
| 5 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 6 | pub struct Probe; | |
| 7 | ||
| 8 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 9 | #[rustc_const_unstable(feature = "const_trait_gate", issue = "none")] | |
| 10 | pub const trait TraitWithConstGate { | |
| 11 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 12 | const ASSOC: usize; | |
| 13 | } | |
| 14 | ||
| 15 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 16 | #[rustc_const_unstable(feature = "const_trait_gate", issue = "none")] | |
| 17 | const impl TraitWithConstGate for Probe { | |
| 18 | const ASSOC: usize = 1; | |
| 19 | } |
tests/ui/traits/default-method/trait-object-lifetime-bound.rs created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/26802>. | |
| 2 | //@ run-pass | |
| 3 | ||
| 4 | trait Foo<'a> { | |
| 5 | fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 } | |
| 6 | } | |
| 7 | ||
| 8 | pub struct FooBar; | |
| 9 | impl Foo<'static> for FooBar {} | |
| 10 | fn test(foobar: FooBar) -> Box<dyn Foo<'static>> { | |
| 11 | Box::new(foobar) | |
| 12 | } | |
| 13 | ||
| 14 | fn main() { | |
| 15 | assert_eq!(test(FooBar).bar(&4), 11); | |
| 16 | } |
tests/ui/traits/object/dyn-iterator-with-non-ord-item.rs created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/26805>. | |
| 2 | //@ run-pass | |
| 3 | ||
| 4 | struct NonOrd; | |
| 5 | ||
| 6 | fn main() { | |
| 7 | let _: Box<dyn Iterator<Item = _>> = Box::new(vec![NonOrd].into_iter()); | |
| 8 | } |
tests/ui/unsized/trait-method-unsized-self-param.rs created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/27078>. | |
| 2 | ||
| 3 | trait Foo { | |
| 4 | const BAR: i32; | |
| 5 | fn foo(self) -> &'static i32 { | |
| 6 | //~^ ERROR the size for values of type | |
| 7 | &<Self>::BAR | |
| 8 | } | |
| 9 | } | |
| 10 | ||
| 11 | fn main() {} |
tests/ui/unsized/trait-method-unsized-self-param.stderr created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | error[E0277]: the size for values of type `Self` cannot be known at compilation time | |
| 2 | --> $DIR/trait-method-unsized-self-param.rs:5:12 | |
| 3 | | | |
| 4 | LL | fn foo(self) -> &'static i32 { | |
| 5 | | ^^^^ doesn't have a size known at compile-time | |
| 6 | | | |
| 7 | = help: unsized fn params are gated as an unstable feature | |
| 8 | help: consider further restricting `Self` | |
| 9 | | | |
| 10 | LL | fn foo(self) -> &'static i32 where Self: Sized { | |
| 11 | | +++++++++++++++++ | |
| 12 | help: function arguments must have a statically known size, borrowed types always have a known size | |
| 13 | | | |
| 14 | LL | fn foo(&self) -> &'static i32 { | |
| 15 | | + | |
| 16 | ||
| 17 | error: aborting due to 1 previous error | |
| 18 | ||
| 19 | For more information about this error, try `rustc --explain E0277`. |