authorbors <bors@rust-lang.org> 2026-06-25 19:36:46 UTC
committerbors <bors@rust-lang.org> 2026-06-25 19:36:46 UTC
logbd08c9e71874a81670fe3938dbf85148e42c2b96
treef916957d1091f90bc7b6e6bdc8f64525a4b6b578
parentfa36a479e492137fdf473a891206da127f132910
parent65153e05af7fa85d2c5b6eac78c9a54673327820

Auto merge of #158416 - JonathanBrouwer:rollup-yCDE4Az, r=JonathanBrouwer

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 {
343343 // This ABI does not support calls at all (except via assembly).
344344 false
345345 }
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
346353 Self::C { .. }
347354 | Self::System { .. }
348355 | Self::Rust
349 | Self::RustCall
350356 | Self::RustCold
351357 | Self::RustInvalid
352358 | 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> {
14591459 );
14601460 }
14611461
1462 fn vscale(&mut self, _: Self::Type) -> Self::Value {
1463 unimplemented!("`rustc_codegen_gcc` doesn't support scalable vectors yet")
1464 }
1465
14621466 fn select(
14631467 &mut self,
14641468 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> {
12261226 }
12271227 }
12281228
1229 fn vscale(&mut self, ty: &'ll Type) -> &'ll Value {
1230 unsafe { llvm::LLVMRustBuildVScale(self.llbuilder, ty) }
1231 }
1232
12291233 fn select(
12301234 &mut self,
12311235 cond: &'ll Value,
compiler/rustc_codegen_llvm/src/builder/autodiff.rs+16-5
......@@ -3,6 +3,9 @@ use std::ptr;
33use rustc_ast::expand::autodiff_attrs::{DiffActivity, DiffMode};
44use rustc_ast::expand::typetree::FncTree;
55use rustc_codegen_ssa::common::TypeKind;
6use rustc_codegen_ssa::mir::IntrinsicResult;
7use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
8use rustc_codegen_ssa::mir::place::PlaceValue;
69use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
710use rustc_data_structures::thin_vec::ThinVec;
811use rustc_hir::attrs::RustcAutodiff;
......@@ -11,7 +14,7 @@ use rustc_middle::{bug, ty};
1114use rustc_target::callconv::PassMode;
1215use tracing::debug;
1316
14use crate::builder::{Builder, PlaceRef, UNNAMED};
17use crate::builder::{Builder, UNNAMED};
1518use crate::context::SimpleCx;
1619use crate::declare::declare_simple_fn;
1720use crate::llvm::{self, TRUE, Type, Value};
......@@ -296,9 +299,10 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
296299 ret_ty: &'ll Type,
297300 fn_args: &[&'ll Value],
298301 attrs: &RustcAutodiff,
299 dest: PlaceRef<'tcx, &'ll Value>,
302 dest_layout: ty::layout::TyAndLayout<'tcx>,
303 dest_place: Option<PlaceValue<&'ll Value>>,
300304 fnc_tree: FncTree,
301) {
305) -> IntrinsicResult<'tcx, &'ll Value> {
302306 // We have to pick the name depending on whether we want forward or reverse mode autodiff.
303307 let mut ad_name: String = match attrs.mode {
304308 DiffMode::Forward => "__enzyme_fwddiff",
......@@ -381,11 +385,18 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
381385 let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
382386
383387 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) {
385389 // If we return void or an empty struct, then our caller (due to how we generated it)
386390 // does not expect a return value. As such, we have no pointer (or place) into which
387391 // we could store our value, and would store into an undef, which would cause UB.
388392 // 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 )
390401 }
391402}
compiler/rustc_codegen_llvm/src/context.rs+1-4
......@@ -978,10 +978,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
978978 }
979979
980980 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)
985982 }
986983}
987984
compiler/rustc_codegen_llvm/src/intrinsic.rs+11-13
......@@ -43,6 +43,7 @@ use crate::errors::{
4343 AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch,
4444 OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic,
4545};
46use crate::intrinsic::ty::typetree::fnc_typetrees;
4647use crate::llvm::{self, Type, Value};
4748use crate::type_of::LayoutLlvmExt;
4849use crate::va_arg::emit_va_arg;
......@@ -223,12 +224,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
223224 )
224225 }
225226 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);
232228 }
233229 sym::offload => {
234230 if tcx.sess.opts.unstable_opts.offload.is_empty() {
......@@ -1728,8 +1724,9 @@ fn codegen_autodiff<'ll, 'tcx>(
17281724 tcx: TyCtxt<'tcx>,
17291725 instance: ty::Instance<'tcx>,
17301726 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> {
17331730 if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) {
17341731 let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutEnable);
17351732 }
......@@ -1769,9 +1766,9 @@ fn codegen_autodiff<'ll, 'tcx>(
17691766 diff_id,
17701767 diff_args
17711768 ),
1772 Err(_) => {
1769 Err(err) => {
17731770 // An error has already been emitted
1774 return;
1771 return IntrinsicResult::Err(err);
17751772 }
17761773 };
17771774
......@@ -1791,7 +1788,7 @@ fn codegen_autodiff<'ll, 'tcx>(
17911788 &mut diff_attrs.input_activity,
17921789 );
17931790
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);
17951792
17961793 // Build body
17971794 generate_enzyme_call(
......@@ -1802,9 +1799,10 @@ fn codegen_autodiff<'ll, 'tcx>(
18021799 llret_ty,
18031800 &val_arr,
18041801 &diff_attrs,
1805 result,
1802 result_layout,
1803 result_place,
18061804 fnc_tree,
1807 );
1805 )
18081806}
18091807
18101808// 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" {
21392139 IsVolatile: bool,
21402140 ) -> &'a Value;
21412141
2142 pub(crate) fn LLVMRustBuildVScale<'a>(B: &Builder<'a>, Ty: &'a Type) -> &'a Value;
2143
21422144 pub(crate) fn LLVMRustTimeTraceProfilerInitialize();
21432145
21442146 pub(crate) fn LLVMRustTimeTraceProfilerFinishThread();
compiler/rustc_codegen_ssa/src/back/link.rs+76-5
......@@ -47,7 +47,7 @@ use rustc_session::{Session, filesearch};
4747use rustc_span::Symbol;
4848use rustc_target::spec::crt_objects::CrtObjects;
4949use rustc_target::spec::{
50 BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents,
50 Arch, BinaryFormat, Cc, CfgAbi, Env, LinkOutputKind, LinkSelfContainedComponents,
5151 LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, Os, RelocModel,
5252 RelroLevel, SanitizerSet, SplitDebuginfo,
5353};
......@@ -2413,6 +2413,69 @@ fn add_rpath_args(
24132413 }
24142414}
24152415
2416fn 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
2420fn 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
24162479fn add_c_staticlib_symbols(
24172480 sess: &Session,
24182481 lib: &NativeLib,
......@@ -2454,7 +2517,14 @@ fn add_c_staticlib_symbols(
24542517 }
24552518
24562519 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 {
24582528 continue;
24592529 }
24602530
......@@ -2469,9 +2539,10 @@ fn add_c_staticlib_symbols(
24692539 _ => continue,
24702540 };
24712541
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));
24752546 }
24762547 }
24772548
compiler/rustc_codegen_ssa/src/traits/builder.rs+11
......@@ -476,6 +476,11 @@ pub trait BuilderMethods<'a, 'tcx>:
476476 flags: MemFlags,
477477 );
478478
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
479484 /// *Typed* copy for non-overlapping places.
480485 ///
481486 /// Has a default implementation in terms of `memcpy`, but specific backends
......@@ -513,6 +518,12 @@ pub trait BuilderMethods<'a, 'tcx>:
513518 temp.val.store_with_flags(self, dst.with_type(layout), flags);
514519 } else if !layout.is_zst() {
515520 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 };
516527 self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, None);
517528 }
518529 }
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp+4
......@@ -1497,6 +1497,10 @@ LLVMRustBuildMemMove(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
14971497 unwrap(Size), IsVolatile));
14981498}
14991499
1500extern "C" LLVMValueRef LLVMRustBuildVScale(LLVMBuilderRef B, LLVMTypeRef Ty) {
1501 return wrap(unwrap(B)->CreateVScale(unwrap(Ty)));
1502}
1503
15001504extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst,
15011505 unsigned DstAlign, LLVMValueRef Val,
15021506 LLVMValueRef Size,
compiler/rustc_middle/src/ty/mod.rs+2-227
......@@ -27,7 +27,6 @@ pub use intrinsic::IntrinsicDef;
2727use rustc_abi::{
2828 Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx,
2929};
30use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
3130use rustc_ast::node_id::NodeMap;
3231use rustc_ast::{self as ast};
3332pub use rustc_ast_ir::{Movability, Mutability, try_visit};
......@@ -67,7 +66,7 @@ pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleF
6766pub use rustc_type_ir::*;
6867#[allow(hidden_glob_reexports, unused_imports)]
6968use rustc_type_ir::{InferCtxtLike, Interner};
70use tracing::{debug, instrument, trace};
69use tracing::{debug, instrument};
7170pub use vtable::*;
7271
7372pub use self::closure::{
......@@ -144,6 +143,7 @@ pub mod print;
144143pub mod relate;
145144pub mod significant_drop_order;
146145pub mod trait_def;
146pub mod typetree;
147147pub mod util;
148148pub mod vtable;
149149
......@@ -2390,228 +2390,3 @@ pub struct DestructuredAdtConst<'tcx> {
23902390 pub variant: VariantIdx,
23912391 pub fields: &'tcx [ty::Const<'tcx>],
23922392}
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.
2397pub 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.
2427pub 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.
2434const MAX_TYPETREE_DEPTH: usize = 6;
2435
2436/// Internal recursive function for TypeTree generation with cycle detection and depth limiting.
2437fn 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.
2459fn 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.
2469fn 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 @@
1use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
2use tracing::trace;
3
4use crate::ty::context::TyCtxt;
5use 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.
10pub 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.
40pub 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.
47const MAX_TYPETREE_DEPTH: usize = 6;
48
49/// Internal implementation with context about whether this is for a reference target.
50fn 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> {
607607 // if possible.
608608 predicates.push_back(bound_predicate.rebind(p));
609609 }
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 }
610616 ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
611617 let p = bound_predicate.rebind(p);
612618 debug!(
......@@ -811,8 +817,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
811817 | ty::PredicateKind::DynCompatible(..)
812818 | ty::PredicateKind::Subtype(..)
813819 | ty::PredicateKind::Coerce(..)
814 | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
815 | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {}
820 | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => {}
816821 ty::PredicateKind::Ambiguous => return false,
817822
818823 // 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 @@
11use crate::any::type_name;
22use crate::clone::TrivialClone;
33use crate::marker::Destruct;
4use crate::mem::ManuallyDrop;
4use crate::mem::{ManuallyDrop, transmute_neo};
55use crate::{fmt, intrinsics, ptr, slice};
66
77/// A wrapper type to construct uninitialized instances of `T`.
......@@ -724,9 +724,9 @@ impl<T> MaybeUninit<T> {
724724 // This also means that `self` must be a `value` variant.
725725 unsafe {
726726 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
728728 // no trace of `ManuallyDrop` in Miri's error messages here.
729 (&raw const self.value).cast::<T>().read()
729 transmute_neo(self)
730730 }
731731 }
732732
library/core/src/mem/mod.rs+5
......@@ -1196,6 +1196,9 @@ pub const unsafe fn transmute_prefix<Src, Dst>(src: Src) -> Dst {
11961196/// New version of `transmute`, exposed under this name so it can be iterated upon
11971197/// without risking breakage to uses of "real" transmute.
11981198///
1199/// Uses a `const`-`assert` to check the sizes instead of typeck hacks,
1200/// but is semantially identical to `transmute` otherwise.
1201///
11991202/// It will not be stabilized under this name.
12001203///
12011204/// # Examples
......@@ -1214,6 +1217,8 @@ pub const unsafe fn transmute_prefix<Src, Dst>(src: Src) -> Dst {
12141217/// unsafe { transmute_neo::<u32, u16>(123) };
12151218/// ```
12161219#[unstable(feature = "transmute_neo", issue = "155079")]
1220#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1221#[inline]
12171222pub const unsafe fn transmute_neo<Src, Dst>(src: Src) -> Dst {
12181223 const { assert!(Src::SIZE == Dst::SIZE) };
12191224
library/std/src/panicking.rs+13-1
......@@ -415,6 +415,7 @@ pub mod panic_count {
415415 //
416416 // This also updates thread-local state to keep track of whether a panic
417417 // hook is currently executing.
418 #[must_use = "MustAbort may not be ignored"]
418419 pub fn increase(run_panic_hook: bool) -> Option<MustAbort> {
419420 let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
420421 if global_count & ALWAYS_ABORT_FLAG != 0 {
......@@ -843,7 +844,18 @@ fn panic_with_hook(
843844/// It just forwards the payload to the panic runtime.
844845#[cfg_attr(panic = "immediate-abort", inline)]
845846pub 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 }
847859
848860 struct RewrapBox(Box<dyn Any + Send>);
849861
src/bootstrap/src/core/build_steps/llvm.rs+5-5
......@@ -169,7 +169,7 @@ pub fn prebuilt_llvm_config(
169169 generate_smart_stamp_hash(
170170 builder,
171171 &builder.config.src.join("src/llvm-project"),
172 &builder.llvm_cache_key(),
172 builder.in_tree_llvm_info.sha().unwrap_or_default(),
173173 )
174174 });
175175
......@@ -999,7 +999,7 @@ impl Step for OmpOffload {
999999 generate_smart_stamp_hash(
10001000 builder,
10011001 &builder.config.src.join("src/llvm-project/offload"),
1002 &builder.llvm_cache_key(),
1002 builder.in_tree_llvm_info.sha().unwrap_or_default(),
10031003 )
10041004 });
10051005 let stamp = BuildStamp::new(&out_dir).with_prefix("offload").add_stamp(smart_stamp_hash);
......@@ -1166,8 +1166,8 @@ impl Step for Enzyme {
11661166 // Enzyme links against LLVM. If we update the LLVM submodule libLLVM might get a new
11671167 // version number, in which case Enzyme will now fail to find LLVM. By including the LLVM
11681168 // 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();
11711171
11721172 static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
11731173 let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
......@@ -1430,7 +1430,7 @@ impl Step for Sanitizers {
14301430 generate_smart_stamp_hash(
14311431 builder,
14321432 &builder.config.src.join("src/llvm-project/compiler-rt"),
1433 &builder.llvm_cache_key(),
1433 builder.in_tree_llvm_info.sha().unwrap_or_default(),
14341434 )
14351435 });
14361436
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
16871687 pub fn exec_ctx(&self) -> &ExecutionContext {
16881688 &self.config.exec_ctx
16891689 }
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 }
17001690}
17011691
17021692/// Return qualified step name, e.g. `compile::Rustc`.
src/bootstrap/src/core/config/config.rs+1-7
......@@ -156,9 +156,6 @@ pub struct Config {
156156 pub backtrace_on_ice: bool,
157157
158158 // llvm codegen options
159 /// Key used to decide when to rebuild LLVM.
160 pub llvm_cache_key: String,
161
162159 pub llvm_assertions: bool,
163160 pub llvm_tests: bool,
164161 pub llvm_enzyme: bool,
......@@ -598,8 +595,6 @@ impl Config {
598595 rustflags: rust_rustflags,
599596 } = toml.rust.unwrap_or_default();
600597
601 let llvm = toml.llvm.unwrap_or_default();
602 let llvm_cache_key = llvm.cache_key();
603598 let Llvm {
604599 optimize: llvm_optimize,
605600 thin_lto: llvm_thin_lto,
......@@ -630,7 +625,7 @@ impl Config {
630625 enable_warnings: llvm_enable_warnings,
631626 download_ci_llvm: llvm_download_ci_llvm,
632627 build_config: llvm_build_config,
633 } = llvm;
628 } = toml.llvm.unwrap_or_default();
634629
635630 let Dist {
636631 sign_folder: dist_sign_folder,
......@@ -1406,7 +1401,6 @@ impl Config {
14061401 llvm_assertions,
14071402 llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false),
14081403 llvm_build_config: llvm_build_config.clone().unwrap_or(Default::default()),
1409 llvm_cache_key,
14101404 llvm_cflags,
14111405 llvm_clang: llvm_clang.unwrap_or(false),
14121406 llvm_clang_cl,
src/bootstrap/src/core/config/toml/llvm.rs-87
......@@ -43,93 +43,6 @@ define_config! {
4343 }
4444}
4545
46impl 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
13346/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options.
13447/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing.
13548#[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.
4141Using `-Zdefault-visibility=interposable` will cause symbols to be emitted with "default"
4242visibility. On platforms that support it, this makes it so that symbols can be interposed, which
4343means that they can be overridden by symbols with the same name from the executable or by other
44shared objects earier in the load order.
44shared 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) {
51855185 errorReport.className = "error";
51865186 errorReport.innerHTML = `Query parser error: "${error.join("")}".`;
51875187 search.insertBefore(errorReport, search.firstElementChild);
5188 } else if (goToFirst ||
5188 } else if (tabNb === 0 && (goToFirst ||
51895189 (count === 1 && getSettingValue("go-to-only-result") === "true")
5190 ) {
5190 )) {
51915191 // Needed to force re-execution of JS when coming back to a page. Let's take this
51925192 // scenario as example:
51935193 //
src/librustdoc/json/conversions.rs+74-2
......@@ -8,9 +8,9 @@ use rustc_data_structures::fx::FxHashSet;
88use rustc_data_structures::thin_vec::ThinVec;
99use rustc_hir as hir;
1010use rustc_hir::attrs::{self, DeprecatedSince, DocAttribute, DocInline, HideOrShow};
11use rustc_hir::def::CtorKind;
11use rustc_hir::def::{CtorKind, DefKind};
1212use rustc_hir::def_id::DefId;
13use rustc_hir::{HeaderSafety, Safety};
13use rustc_hir::{HeaderSafety, Safety, find_attr};
1414use rustc_metadata::rendered_const;
1515use rustc_middle::ty::TyCtxt;
1616use rustc_middle::{bug, ty};
......@@ -92,6 +92,9 @@ impl JsonRenderer<'_> {
9292 item.item_id.as_def_id()
9393 };
9494 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 });
9598
9699 Some(Item {
97100 id,
......@@ -100,6 +103,7 @@ impl JsonRenderer<'_> {
100103 span: span.and_then(|span| span.into_json(self)),
101104 visibility: visibility.into_json(self),
102105 stability: stability.map(|s| Box::new(s.into_json(self))),
106 const_stability,
103107 docs,
104108 attrs,
105109 deprecation: deprecation.into_json(self),
......@@ -246,6 +250,24 @@ impl FromClean<hir::Stability> for Stability {
246250 }
247251}
248252
253impl 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
249271impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> {
250272 fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
251273 use clean::GenericArgs::*;
......@@ -948,6 +970,55 @@ impl FromClean<ItemType> for ItemKind {
948970 }
949971}
950972
973fn 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
9511022/// Maybe convert a attribute from hir to json.
9521023///
9531024/// 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<'_>)
9661037 vec![match kind {
9671038 AK::Deprecated { .. } => return Vec::new(), // Handled separately into Item::deprecation.
9681039 AK::Stability { .. } => return Vec::new(), // Handled separately into Item::stability
1040 AK::RustcConstStability { .. } => return Vec::new(), // Handled separately into Item::const_stability.
9691041
9701042 AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"),
9711043
src/librustdoc/json/mod.rs+1-1
......@@ -361,6 +361,6 @@ mod size_asserts {
361361 // tidy-alphabetical-end
362362
363363 // 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>());
365365 static_assert_size!(ExternalCrate, 48 + size_of::<std::path::PathBuf>());
366366}
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
114114// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
115115// are deliberately not in a doc comment, because they need not be in public docs.)
116116//
117// Latest feature: Add `Item::stability`.
118pub const FORMAT_VERSION: u32 = 58;
117// Latest feature: Add `Item::const_stability`.
118pub const FORMAT_VERSION: u32 = 59;
119119
120120/// The root of the emitted JSON blob.
121121///
......@@ -286,6 +286,8 @@ pub struct Item {
286286 /// - `#[doc = "Doc Comment"]` or `/// Doc comment`: see [`Self::docs`] instead.
287287 /// - `#[deprecated]` attributes: see the [`Self::deprecation`] field instead.
288288 /// - `#[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.
289291 ///
290292 /// Attributes appear in pretty-printed Rust form, regardless of their formatting
291293 /// in the original source code. For example:
......@@ -319,20 +321,31 @@ pub struct Item {
319321 /// most ordinary third-party crates usually have no data here.
320322 pub stability: Option<Box<Stability>>,
321323
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
322334 /// The type-specific fields describing this item.
323335 pub inner: ItemEnum,
324336}
325337
326338/// Stability information for an item.
327339///
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]`.
331344#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
332345#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
333346#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
334347pub struct Stability {
335 /// The stability feature associated with this item.
348 /// The feature associated with this stability record.
336349 ///
337350 /// For unstable items, this is the feature gate associated with the item.
338351 /// For stable items, this is the historical label recorded when the item was stabilized.
......@@ -342,7 +355,6 @@ pub struct Stability {
342355 pub level: StabilityLevel,
343356}
344357
345/// Whether an item is stable or unstable as regular public API.
346358#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
347359#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
348360#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
......@@ -365,6 +377,8 @@ pub enum StabilityLevel {
365377/// - `#[doc = "Doc Comment"]` or `/// Doc comment`. These are in [`Item::docs`] instead.
366378/// - `#[deprecated]`. These are in [`Item::deprecation`] instead.
367379/// - `#[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.
368382pub enum Attribute {
369383 /// `#[non_exhaustive]`
370384 NonExhaustive,
src/tools/jsondoclint/src/validator/tests.rs+7
......@@ -34,6 +34,7 @@ fn errors_on_missing_links() {
3434 attrs: vec![],
3535 deprecation: None,
3636 stability: None,
37 const_stability: None,
3738 inner: ItemEnum::Module(Module {
3839 is_crate: true,
3940 items: vec![],
......@@ -83,6 +84,7 @@ fn errors_on_local_in_paths_and_not_index() {
8384 attrs: Vec::new(),
8485 deprecation: None,
8586 stability: None,
87 const_stability: None,
8688 inner: ItemEnum::Module(Module {
8789 is_crate: true,
8890 items: vec![Id(1)],
......@@ -103,6 +105,7 @@ fn errors_on_local_in_paths_and_not_index() {
103105 attrs: Vec::new(),
104106 deprecation: None,
105107 stability: None,
108 const_stability: None,
106109 inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }),
107110 },
108111 ),
......@@ -157,6 +160,7 @@ fn errors_on_missing_path() {
157160 attrs: Vec::new(),
158161 deprecation: None,
159162 stability: None,
163 const_stability: None,
160164 inner: ItemEnum::Module(Module {
161165 is_crate: true,
162166 items: vec![Id(1), Id(2)],
......@@ -177,6 +181,7 @@ fn errors_on_missing_path() {
177181 attrs: Vec::new(),
178182 deprecation: None,
179183 stability: None,
184 const_stability: None,
180185 inner: ItemEnum::Struct(Struct {
181186 kind: StructKind::Unit,
182187 generics: generics.clone(),
......@@ -197,6 +202,7 @@ fn errors_on_missing_path() {
197202 attrs: Vec::new(),
198203 deprecation: None,
199204 stability: None,
205 const_stability: None,
200206 inner: ItemEnum::Function(Function {
201207 sig: FunctionSignature {
202208 inputs: vec![],
......@@ -260,6 +266,7 @@ fn checks_local_crate_id_is_correct() {
260266 attrs: Vec::new(),
261267 deprecation: None,
262268 stability: None,
269 const_stability: None,
263270 inner: ItemEnum::Module(Module {
264271 is_crate: true,
265272 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
11use std::arch::aarch64::*;
12
13#[allow(improper_ctypes)]
14unsafe 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
31pub 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 @@
11//@ ignore-nvptx64
22//@ ignore-wasm
33//@ 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
84// Reason: the compiled binary is executed
95
106use 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,
129};
1310
1411fn 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();
1715
1816 rustc().input("foo.rs").arg("-lstatic=foo").crate_type("cdylib").run();
1917
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"));
2431
2532 rustc().input("foo_export.rs").arg("-lstatic:+export-symbols=foo").crate_type("cdylib").run();
2633
2734 if is_darwin() {
28 let out = llvm_nm()
35 llvm_nm()
2936 .input(dynamic_lib_name("foo_export"))
3037 .run()
3138 .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");
3245 } else if is_aix() {
33 let out = llvm_nm()
46 llvm_nm()
3447 .input(dynamic_lib_name("foo_export"))
3548 .run()
3649 .assert_stdout_contains("T .my_function");
3750 } else {
38 let out = llvm_nm()
51 llvm_nm()
3952 .input(dynamic_lib_name("foo_export"))
4053 .run()
4154 .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"}
3333
3434go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
3535// We enter it into the search.
36click: "#search-button"
37wait-for: "#alternative-display .search-input"
3638write-into: (".search-input", "HasALongTraitWithParams")
3739wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"}
38assert-window-property: ({"location": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
40assert-window-property: ({"location"."pathname": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
3941
4042// Regression test for <https://github.com/rust-lang/rust/issues/112676>.
4143// If "go-to-only-result" is enabled and you go back to history, it should not lead you back to the
4244// page result again automatically.
4345history-go-back:
4446wait-for-document-property: {"title": "lib2 - Rust"}
45assert-window-property: ({"location": "/lib2/index.html"}, ENDS_WITH)
47assert-window-property: ({"location"."pathname": "/lib2/index.html"}, ENDS_WITH)
4648
4749// We try again to see if it goes to the only result
4850go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams"
......@@ -69,3 +71,43 @@ call-function: ("check-setting", {
6971 "storage_value": "false",
7072 "setting_attribute_value": "false",
7173})
74
75define-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.
97go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
98
99// The setting should be disabled.
100assert-local-storage-false: {"rustdoc-go-to-only-result": "true"}
101store-window-property: {"location"."pathname": location}
102click: "#search-button"
103wait-for: "#alternative-display .search-input"
104write-into: (".search-input", "Whitespace")
105call-function: ("search-multiple-results", {"location": |location|})
106
107// We now toggle the setting and reload the page.
108call-function: ("open-settings-menu", {})
109click: "#go-to-only-result"
110assert-local-storage: {"rustdoc-go-to-only-result": "true"}
111
112reload:
113call-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")]
5pub 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")]
17pub 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")]
28pub 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")]
42pub 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")]
50pub 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
55pub 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")]
4pub struct ConstTraitTarget;
5
6#[stable(feature = "const_stable_trait_target_feature", since = "1.0.0")]
7pub struct ConstStableTraitTarget;
8
9#[stable(feature = "inherent_const_method_target_feature", since = "1.1.0")]
10pub struct InherentConstMethodTarget;
11
12impl 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")]
32pub 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")]
63pub 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")]
84const 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")]
118pub 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")]
147const 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 @@
44
55//@ normalize-stderr: "note: compiler flags.*\n\n" -> ""
66//@ 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" -> ""
88//@ normalize-stderr: " +\d{1,}: .*\n" -> ""
99//@ normalize-stderr: " + at .*\n" -> ""
1010//@ normalize-stderr: ".*note: Some details are omitted.*\n" -> ""
tests/rustdoc-ui/ice-bug-report-url.stderr-2
......@@ -5,8 +5,6 @@ LL | fn wrong()
55 | ^ expected one of `->`, `where`, or `{`
66
77
8
9aborting due to `-Z treat-err-as-bug=1`
108stack backtrace:
119
1210error: 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
7pub struct Inner<T>(T);
8
9pub struct Outer<T>(Inner<T>);
10
11impl<T> Unpin for Inner<T>
12where
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)]
5pub struct Foo {
6 x: isize,
7 y: isize
8}
9
10impl Foo {
11 #[allow(improper_ctypes_definitions)]
12 pub extern "C" fn foo_new() -> Foo {
13 Foo { x: 21, y: 33 }
14 }
15}
16
17fn main() {}
tests/ui/async-await/higher-ranked-auto-trait-18.no_assumptions.stderr created+13
......@@ -0,0 +1,13 @@
1error: higher-ranked lifetime error
2 --> $DIR/higher-ranked-auto-trait-18.rs:69:5
3 |
4LL | / require_send(async {
5LL | | let r = Receiver::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData };
6LL | | let _ = r.await;
7LL | | });
8 | |______^
9 |
10 = note: could not prove `{async block@$DIR/higher-ranked-auto-trait-18.rs:69:18: 69:23}: Send`
11
12error: 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
21use std::cell::Cell;
22use std::future::Future;
23use std::marker::PhantomData;
24use std::pin::Pin;
25use std::task::{Context, Poll};
26
27// --- PhantomData<*mut ()> version: needs `unsafe impl Send` ---
28
29struct Receiver<T: Send + 'static> {
30 _value: Option<T>,
31 _not_sync: PhantomData<*mut ()>,
32}
33
34unsafe impl<T: Send + 'static> Send for Receiver<T> {}
35
36impl<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
45struct ReceiverCell<T: Send + 'static> {
46 _value: Option<T>,
47 _not_sync: PhantomData<Cell<()>>,
48}
49
50impl<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
57trait MyTrait: Send {}
58
59fn require_send<F: Future + Send>(_f: F) {}
60
61fn 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
4fn 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
4use std::cell::RefCell;
5use std::rc::Rc;
6
7pub struct Callbacks {
8 callbacks: Vec<Rc<RefCell<dyn FnMut(i32)>>>,
9}
10
11impl 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
17fn 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
8struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(dead_code)] T);
9
10impl<'a, T: ?Sized> Drop for Wrapper<'a, T> {
11 fn drop(&mut self) {
12 *self.0 = 432;
13 }
14}
15
16fn 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
8use std::sync::atomic::{Ordering, AtomicUsize};
9use std::thread;
10
11static LOG: AtomicUsize = AtomicUsize::new(0);
12
13enum WithDtor { Val }
14impl Drop for WithDtor {
15 fn drop(&mut self) {
16 LOG.store(LOG.load(Ordering::SeqCst)+1,Ordering::SeqCst);
17 }
18}
19
20pub 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
11extern "rust-call" fn a(_: ()) {
12 become a(());
13 //~^ error: ABI does not support guaranteed tail calls
14}
15
16fn main() {}
tests/ui/explicit-tail-calls/unsupported-abi/rust-call.stderr created+10
......@@ -0,0 +1,10 @@
1error: ABI does not support guaranteed tail calls
2 --> $DIR/rust-call.rs:12:5
3 |
4LL | become a(());
5 | ^^^^^^^^^^^^
6 |
7 = note: `become` is not supported for `extern "rust-call"` functions
8
9error: 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
3fn 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 @@
1error[E0436]: functional record update syntax requires a struct
2 --> $DIR/fru-on-enum-variant.rs:6:22
3 |
4LL | Foo::A { x: 6, ..orig };
5 | ^^^^
6
7error: aborting due to 1 previous error
8
9For 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
8use std::sync::atomic::{Ordering, AtomicUsize};
9use std::thread;
10
11static LOG: AtomicUsize = AtomicUsize::new(0);
12
13enum WithDtor { Val }
14impl Drop for WithDtor {
15 fn drop(&mut self) {
16 LOG.store(LOG.load(Ordering::SeqCst)+1,Ordering::SeqCst);
17 }
18}
19
20pub 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
2struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(dead_code)] T);
3
4impl<'a, T: ?Sized> Drop for Wrapper<'a, T> {
5 fn drop(&mut self) {
6 *self.0 = 432;
7 }
8}
9
10fn 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
2trait Foo<'a> {
3 fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 }
4}
5
6pub struct FooBar;
7impl Foo<'static> for FooBar {}
8fn test(foobar: FooBar) -> Box<dyn Foo<'static>> {
9 Box::new(foobar)
10}
11
12fn 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
2struct NonOrd;
3
4fn 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 @@
1fn 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 @@
1error[E0436]: functional record update syntax requires a struct
2 --> $DIR/issue-26948.rs:4:22
3 |
4LL | Foo::A { x: 6, ..orig };
5 | ^^^^
6
7error: aborting due to 1 previous error
8
9For 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)]
3pub struct Foo {
4 x: isize,
5 y: isize
6}
7
8impl Foo {
9 #[allow(improper_ctypes_definitions)]
10 pub extern "C" fn foo_new() -> Foo {
11 Foo { x: 21, y: 33 }
12 }
13}
14
15fn 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
3fn 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 @@
1warning: denote infinite loops with `loop { ... }`
2 --> $DIR/issue-27042.rs:8:9
3 |
4LL | / 'b:
5LL | |
6LL | | while true { break }; // but here we cite the whole loop
7 | |__________________^ help: use `loop`
8 |
9 = note: `#[warn(while_true)]` on by default
10
11error[E0308]: mismatched types
12 --> $DIR/issue-27042.rs:6:16
13 |
14LL | let _: i32 =
15 | - expected because of this assignment
16LL | 'a: // in this case, the citation is just the `break`:
17LL | loop { break };
18 | ---- ^^^^^ expected `i32`, found `()`
19 | |
20 | this loop is expected to be of type `i32`
21 |
22help: give the `break` a value of the expected type
23 |
24LL | loop { break 42 };
25 | ++
26
27error[E0308]: mismatched types
28 --> $DIR/issue-27042.rs:8:9
29 |
30LL | let _: i32 =
31 | --- expected due to this
32LL | / 'b:
33LL | |
34LL | | while true { break }; // but here we cite the whole loop
35 | |____________________________^ expected `i32`, found `()`
36
37error[E0308]: mismatched types
38 --> $DIR/issue-27042.rs:12:9
39 |
40LL | / 'c:
41LL | | 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
46error[E0308]: mismatched types
47 --> $DIR/issue-27042.rs:15:9
48 |
49LL | let _: i32 =
50 | --- expected due to this
51LL | / 'd:
52LL | | while let Some(_) = None { break };
53 | |__________________________________________^ expected `i32`, found `()`
54
55error: aborting due to 4 previous errors; 1 warning emitted
56
57For 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
2fn 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 @@
1trait 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
9fn main() {}
tests/ui/issues/issue-27078.stderr deleted-19
......@@ -1,19 +0,0 @@
1error[E0277]: the size for values of type `Self` cannot be known at compilation time
2 --> $DIR/issue-27078.rs:3:12
3 |
4LL | 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
8help: consider further restricting `Self`
9 |
10LL | fn foo(self) -> &'static i32 where Self: Sized {
11 | +++++++++++++++++
12help: function arguments must have a statically known size, borrowed types always have a known size
13 |
14LL | fn foo(&self) -> &'static i32 {
15 | +
16
17error: aborting due to 1 previous error
18
19For more information about this error, try `rustc --explain E0277`.
tests/ui/issues/issue-27105.rs deleted-15
......@@ -1,15 +0,0 @@
1//@ check-pass
2use std::cell::RefCell;
3use std::rc::Rc;
4
5pub struct Callbacks {
6 callbacks: Vec<Rc<RefCell<dyn FnMut(i32)>>>,
7}
8
9impl 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
15fn 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
4fn 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 @@
1warning: denote infinite loops with `loop { ... }`
2 --> $DIR/loop-label-included-in-span.rs:9:9
3 |
4LL | / 'b:
5LL | |
6LL | | while true { break }; // but here we cite the whole loop
7 | |__________________^ help: use `loop`
8 |
9 = note: `#[warn(while_true)]` on by default
10
11error[E0308]: mismatched types
12 --> $DIR/loop-label-included-in-span.rs:7:16
13 |
14LL | let _: i32 =
15 | - expected because of this assignment
16LL | 'a: // in this case, the citation is just the `break`:
17LL | loop { break };
18 | ---- ^^^^^ expected `i32`, found `()`
19 | |
20 | this loop is expected to be of type `i32`
21 |
22help: give the `break` a value of the expected type
23 |
24LL | loop { break 42 };
25 | ++
26
27error[E0308]: mismatched types
28 --> $DIR/loop-label-included-in-span.rs:9:9
29 |
30LL | let _: i32 =
31 | --- expected due to this
32LL | / 'b:
33LL | |
34LL | | while true { break }; // but here we cite the whole loop
35 | |____________________________^ expected `i32`, found `()`
36
37error[E0308]: mismatched types
38 --> $DIR/loop-label-included-in-span.rs:13:9
39 |
40LL | / 'c:
41LL | | 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
46error[E0308]: mismatched types
47 --> $DIR/loop-label-included-in-span.rs:16:9
48 |
49LL | let _: i32 =
50 | --- expected due to this
51LL | / 'd:
52LL | | while let Some(_) = None { break };
53 | |__________________________________________^ expected `i32`, found `()`
54
55error: aborting due to 4 previous errors; 1 warning emitted
56
57For 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() {
6161 bomb_out_but_not_abort("joined - but we were supposed to panic!");
6262}
6363
64fn 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
6472fn main() {
6573 let tests: &[(_, fn())] = &[
6674 ("test", test),
6775 ("test_always_abort", test_always_abort),
6876 ("test_always_abort_thread", test_always_abort_thread),
77 ("test_always_abort_resume_unwind", test_always_abort_resume_unwind),
6978 ];
7079
7180 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
9use std::panic;
10
11fn 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 @@
1panicked at $DIR/panic-in-hook.rs:12:34:
2
3thread 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
9use std::panic;
10
11fn 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 @@
1thread 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
4extern crate associated_const_stability;
5
6use 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
18const VALUE: usize = <Probe as TraitWithConstGate>::ASSOC;
19
20const fn example<T: TraitWithConstGate>(_: &T) -> usize {
21 <T as TraitWithConstGate>::ASSOC
22}
23
24fn 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")]
6pub struct Probe;
7
8#[stable(feature = "rust1", since = "1.0.0")]
9#[rustc_const_unstable(feature = "const_trait_gate", issue = "none")]
10pub 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")]
17const 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
4trait Foo<'a> {
5 fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 }
6}
7
8pub struct FooBar;
9impl Foo<'static> for FooBar {}
10fn test(foobar: FooBar) -> Box<dyn Foo<'static>> {
11 Box::new(foobar)
12}
13
14fn 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
4struct NonOrd;
5
6fn 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
3trait 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
11fn main() {}
tests/ui/unsized/trait-method-unsized-self-param.stderr created+19
......@@ -0,0 +1,19 @@
1error[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 |
4LL | 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
8help: consider further restricting `Self`
9 |
10LL | fn foo(self) -> &'static i32 where Self: Sized {
11 | +++++++++++++++++
12help: function arguments must have a statically known size, borrowed types always have a known size
13 |
14LL | fn foo(&self) -> &'static i32 {
15 | +
16
17error: aborting due to 1 previous error
18
19For more information about this error, try `rustc --explain E0277`.