| author | bors <bors@rust-lang.org> 2026-06-25 22:48:30 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-25 22:48:30 UTC |
| log | 40557f6225e337d68c8d4f086557ce54135f5dd9 |
| tree | ad34357ff35cbcc244cdc8783802499b6d53e3be |
| parent | bd08c9e71874a81670fe3938dbf85148e42c2b96 |
| parent | d109bb0266a90767d866725ecda219aa73aa5fce |
Rollup of 10 pull requests
Successful merges:
- rust-lang/rust#158410 (Update LLVM for Mach-O __LINKEDIT alignment fix.)
- rust-lang/rust#157397 (cmse: clear padding when crossing the secure boundary)
- rust-lang/rust#158036 (Add -Zinstrument-mcount=fentry to -Zinstrument-mcount)
- rust-lang/rust#158330 (llvm: use intrinsics for f16, f32 minimum/maximum)
- rust-lang/rust#158359 (fix(tests): allow either branch direction in ilog_known_base)
- rust-lang/rust#158067 (LLVM 23: Adapt codegen test to moved assume)
- rust-lang/rust#158261 (Move part of the target checking for `#[may_dangle]` to the parser)
- rust-lang/rust#158358 (Fix invalid E0609 raw pointer deref suggestion inside macros)
- rust-lang/rust#158392 (delegation: add tests for defaults and infers in generics)
- rust-lang/rust#158394 (Generate synthetic generic args only for delegation's child segment)68 files changed, 1866 insertions(+), 753 deletions(-)
compiler/rustc_abi/src/layout/ty.rs+87-1| ... | ... | @@ -1,7 +1,8 @@ |
| 1 | 1 | use std::fmt; |
| 2 | use std::ops::Deref; | |
| 2 | use std::ops::{Deref, Range}; | |
| 3 | 3 | |
| 4 | 4 | use rustc_data_structures::intern::Interned; |
| 5 | use rustc_data_structures::range_set::RangeSet; | |
| 5 | 6 | use rustc_macros::StableHash; |
| 6 | 7 | |
| 7 | 8 | use crate::layout::{FieldIdx, VariantIdx}; |
| ... | ... | @@ -282,4 +283,89 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { |
| 282 | 283 | } |
| 283 | 284 | found |
| 284 | 285 | } |
| 286 | ||
| 287 | /// The ranges of bytes that are always ignored by the representation relation of this type. | |
| 288 | /// | |
| 289 | /// In other words, for any sequence of bytes, if we reset the these padding bytes to uninit, | |
| 290 | /// then these two sequences of bytes represent the same value (or they are both invalid). | |
| 291 | /// This is the "guaranteed" padding. There may be more bytes that are padding for some | |
| 292 | /// but not all variants of this type; those are not included. | |
| 293 | /// (E.g. `Option<i8>` has no guaranteed padding so the empty range set is returned, but its `None` value still has padding). | |
| 294 | pub fn padding_ranges<C>(&self, cx: &C) -> Vec<Range<Size>> | |
| 295 | where | |
| 296 | Ty: TyAbiInterface<'a, C> + Copy, | |
| 297 | { | |
| 298 | let mut data = RangeSet::new(); | |
| 299 | self.add_data_ranges(cx, Size::ZERO, &mut data); | |
| 300 | ||
| 301 | // Find gaps between the data ranges. | |
| 302 | let mut uninit_ranges = Vec::new(); | |
| 303 | let mut covered_until = Size::ZERO; | |
| 304 | for &(offset, size) in data.0.iter() { | |
| 305 | if offset > covered_until { | |
| 306 | uninit_ranges.push(covered_until..offset); | |
| 307 | } | |
| 308 | covered_until = Ord::max(covered_until, offset + size); | |
| 309 | } | |
| 310 | ||
| 311 | // Add trailing padding. | |
| 312 | if self.size > covered_until { | |
| 313 | uninit_ranges.push(covered_until..self.size); | |
| 314 | } | |
| 315 | ||
| 316 | uninit_ranges | |
| 317 | } | |
| 318 | ||
| 319 | /// Extend `out` with all ranges of bytes that *may* carry relevant data for values of this type. | |
| 320 | /// For enums and unions there are offsets that are initialized for some | |
| 321 | /// variants but not for others; those offset *will* get added to `out`. | |
| 322 | fn add_data_ranges<C>(self, cx: &C, base_offset: Size, out: &mut RangeSet<Size>) | |
| 323 | where | |
| 324 | Ty: TyAbiInterface<'a, C> + Copy, | |
| 325 | { | |
| 326 | if self.is_zst() { | |
| 327 | return; | |
| 328 | } | |
| 329 | ||
| 330 | match &self.variants { | |
| 331 | Variants::Empty => { /* done */ } | |
| 332 | Variants::Single { index: _ } => match &self.fields { | |
| 333 | FieldsShape::Primitive => { | |
| 334 | out.add_range(base_offset, self.size); | |
| 335 | } | |
| 336 | &FieldsShape::Union(field_count) => { | |
| 337 | for field in 0..field_count.get() { | |
| 338 | let field = self.field(cx, field); | |
| 339 | field.add_data_ranges(cx, base_offset, out); | |
| 340 | } | |
| 341 | } | |
| 342 | &FieldsShape::Array { stride, count } => { | |
| 343 | let elem = self.field(cx, 0); | |
| 344 | ||
| 345 | // For scalars we know there is no padding between the elements, | |
| 346 | // so the entire array is a single big data range. | |
| 347 | if elem.backend_repr.is_scalar() { | |
| 348 | out.add_range(base_offset, elem.size * count); | |
| 349 | } else { | |
| 350 | // FIXME: this is really inefficient for large arrays. | |
| 351 | for idx in 0..count { | |
| 352 | elem.add_data_ranges(cx, base_offset + idx * stride, out); | |
| 353 | } | |
| 354 | } | |
| 355 | } | |
| 356 | FieldsShape::Arbitrary { offsets, in_memory_order: _ } => { | |
| 357 | for (field, &offset) in offsets.iter_enumerated() { | |
| 358 | let field = self.field(cx, field.as_usize()); | |
| 359 | field.add_data_ranges(cx, base_offset + offset, out); | |
| 360 | } | |
| 361 | } | |
| 362 | }, | |
| 363 | Variants::Multiple { variants, .. } => { | |
| 364 | for variant in variants.indices() { | |
| 365 | let variant = self.for_variant(cx, variant); | |
| 366 | variant.add_data_ranges(cx, base_offset, out); | |
| 367 | } | |
| 368 | } | |
| 369 | } | |
| 370 | } | |
| 285 | 371 | } |
compiler/rustc_abi/src/lib.rs+1-1| ... | ... | @@ -792,7 +792,7 @@ impl FromStr for Endian { |
| 792 | 792 | } |
| 793 | 793 | |
| 794 | 794 | /// Size of a type in bytes. |
| 795 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
| 795 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] | |
| 796 | 796 | #[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))] |
| 797 | 797 | pub struct Size { |
| 798 | 798 | raw: u64, |
compiler/rustc_attr_parsing/src/attributes/semantics.rs+7-1| ... | ... | @@ -1,11 +1,17 @@ |
| 1 | 1 | use rustc_feature::AttributeStability; |
| 2 | use rustc_hir::target::GenericParamKind; | |
| 2 | 3 | |
| 3 | 4 | use super::prelude::*; |
| 4 | 5 | |
| 5 | 6 | pub(crate) struct MayDangleParser; |
| 6 | 7 | impl NoArgsAttributeParser for MayDangleParser { |
| 7 | 8 | const PATH: &[Symbol] = &[sym::may_dangle]; |
| 8 | const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` | |
| 9 | const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ | |
| 10 | Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: false }), | |
| 11 | Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }), | |
| 12 | Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false }), | |
| 13 | Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: true }), | |
| 14 | ]); | |
| 9 | 15 | const STABILITY: AttributeStability = unstable!(dropck_eyepatch); |
| 10 | 16 | const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; |
| 11 | 17 | } |
compiler/rustc_attr_parsing/src/target_checking.rs+1| ... | ... | @@ -416,6 +416,7 @@ pub(crate) fn allowed_targets_applied( |
| 416 | 416 | |
| 417 | 417 | // ensure a consistent order |
| 418 | 418 | target_strings.sort(); |
| 419 | target_strings.dedup(); | |
| 419 | 420 | |
| 420 | 421 | // If there is now only 1 target left, show that as the only possible target |
| 421 | 422 | let only_target = target_strings.len() == 1; |
compiler/rustc_codegen_llvm/src/attributes.rs+25-15| ... | ... | @@ -7,7 +7,9 @@ use rustc_middle::middle::codegen_fn_attrs::{ |
| 7 | 7 | TargetFeature, |
| 8 | 8 | }; |
| 9 | 9 | use rustc_middle::ty::{self, Instance, TyCtxt}; |
| 10 | use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet}; | |
| 10 | use rustc_session::config::{ | |
| 11 | BranchProtection, FunctionReturn, InstrumentMcount, OptLevel, PAuthKey, PacRet, | |
| 12 | }; | |
| 11 | 13 | use rustc_span::sym; |
| 12 | 14 | use rustc_symbol_mangling::mangle_internal_symbol; |
| 13 | 15 | use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector}; |
| ... | ... | @@ -177,7 +179,7 @@ pub(crate) fn frame_pointer(sess: &Session) -> FramePointer { |
| 177 | 179 | let opts = &sess.opts; |
| 178 | 180 | // "mcount" function relies on stack pointer. |
| 179 | 181 | // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>. |
| 180 | if opts.unstable_opts.instrument_mcount { | |
| 182 | if opts.unstable_opts.instrument_mcount == InstrumentMcount::Mcount { | |
| 181 | 183 | fp.ratchet(FramePointer::Always); |
| 182 | 184 | } |
| 183 | 185 | fp.ratchet(opts.cg.force_frame_pointers); |
| ... | ... | @@ -214,7 +216,7 @@ fn instrument_function_attr<'ll>( |
| 214 | 216 | instrument_fn: InstrumentFnAttr, |
| 215 | 217 | ) -> SmallVec<[&'ll Attribute; 4]> { |
| 216 | 218 | let mut attrs = SmallVec::new(); |
| 217 | if sess.opts.unstable_opts.instrument_mcount { | |
| 219 | if sess.opts.unstable_opts.instrument_mcount != InstrumentMcount::Disabled { | |
| 218 | 220 | // Similar to `clang -pg` behavior. Handled by the |
| 219 | 221 | // `post-inline-ee-instrument` LLVM pass. |
| 220 | 222 | |
| ... | ... | @@ -224,18 +226,26 @@ fn instrument_function_attr<'ll>( |
| 224 | 226 | }; |
| 225 | 227 | |
| 226 | 228 | if instrument_entry { |
| 227 | // The function name varies on platforms. | |
| 228 | // See test/CodeGen/mcount.c in clang. | |
| 229 | let mcount_name = match &sess.target.llvm_mcount_intrinsic { | |
| 230 | Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(), | |
| 231 | None => sess.target.mcount.as_ref(), | |
| 232 | }; | |
| 233 | ||
| 234 | attrs.push(llvm::CreateAttrStringValue( | |
| 235 | cx.llcx, | |
| 236 | "instrument-function-entry-inlined", | |
| 237 | mcount_name, | |
| 238 | )); | |
| 229 | match sess.opts.unstable_opts.instrument_mcount { | |
| 230 | InstrumentMcount::Mcount => { | |
| 231 | // The function name varies on platforms. | |
| 232 | // See test/CodeGen/mcount.c in clang. | |
| 233 | let mcount_name = match &sess.target.llvm_mcount_intrinsic { | |
| 234 | Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(), | |
| 235 | None => sess.target.mcount.as_ref(), | |
| 236 | }; | |
| 237 | ||
| 238 | attrs.push(llvm::CreateAttrStringValue( | |
| 239 | cx.llcx, | |
| 240 | "instrument-function-entry-inlined", | |
| 241 | mcount_name, | |
| 242 | )); | |
| 243 | } | |
| 244 | InstrumentMcount::Fentry => { | |
| 245 | attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true")); | |
| 246 | } | |
| 247 | InstrumentMcount::Disabled => {} | |
| 248 | } | |
| 239 | 249 | } |
| 240 | 250 | } |
| 241 | 251 | if let Some(options) = &sess.opts.unstable_opts.instrument_xray { |
compiler/rustc_codegen_llvm/src/intrinsic.rs+4-4| ... | ... | @@ -114,17 +114,17 @@ fn call_simple_intrinsic<'ll, 'tcx>( |
| 114 | 114 | sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]), |
| 115 | 115 | sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]), |
| 116 | 116 | |
| 117 | sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), | |
| 118 | sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), | |
| 117 | 119 | // FIXME: LLVM currently mis-compile those intrinsics, re-enable them |
| 118 | 120 | // when llvm/llvm-project#{139380,139381,140445} are fixed. |
| 119 | //sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), | |
| 120 | //sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), | |
| 121 | 121 | //sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), |
| 122 | 122 | //sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), |
| 123 | 123 | // |
| 124 | sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), | |
| 125 | sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), | |
| 124 | 126 | // FIXME: LLVM currently mis-compile those intrinsics, re-enable them |
| 125 | 127 | // when llvm/llvm-project#{139380,139381,140445} are fixed. |
| 126 | //sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), | |
| 127 | //sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), | |
| 128 | 128 | //sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), |
| 129 | 129 | //sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), |
| 130 | 130 | // |
compiler/rustc_codegen_ssa/src/back/link.rs+3-3| ... | ... | @@ -35,8 +35,8 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; |
| 35 | 35 | use rustc_middle::middle::dependency_format::Linkage; |
| 36 | 36 | use rustc_middle::middle::exported_symbols::SymbolExportKind; |
| 37 | 37 | use rustc_session::config::{ |
| 38 | self, CFGuard, CrateType, DebugInfo, LinkerFeaturesCli, OutFileName, OutputFilenames, | |
| 39 | OutputType, PrintKind, SplitDwarfKind, Strip, | |
| 38 | self, CFGuard, CrateType, DebugInfo, InstrumentMcount, LinkerFeaturesCli, OutFileName, | |
| 39 | OutputFilenames, OutputType, PrintKind, SplitDwarfKind, Strip, | |
| 40 | 40 | }; |
| 41 | 41 | use rustc_session::lint::builtin::LINKER_MESSAGES; |
| 42 | 42 | use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; |
| ... | ... | @@ -2953,7 +2953,7 @@ fn add_order_independent_options( |
| 2953 | 2953 | cmd.pgo_gen(); |
| 2954 | 2954 | } |
| 2955 | 2955 | |
| 2956 | if sess.opts.unstable_opts.instrument_mcount { | |
| 2956 | if sess.opts.unstable_opts.instrument_mcount != InstrumentMcount::Disabled { | |
| 2957 | 2957 | cmd.enable_profiling(); |
| 2958 | 2958 | } |
| 2959 | 2959 |
compiler/rustc_codegen_ssa/src/mir/block.rs+71-2| ... | ... | @@ -1,6 +1,9 @@ |
| 1 | 1 | use std::cmp; |
| 2 | use std::ops::Range; | |
| 2 | 3 | |
| 3 | use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange}; | |
| 4 | use rustc_abi::{ | |
| 5 | Align, ArmCall, BackendRepr, CanonAbi, ExternAbi, HasDataLayout, Reg, Size, WrappingRange, | |
| 6 | }; | |
| 4 | 7 | use rustc_ast as ast; |
| 5 | 8 | use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; |
| 6 | 9 | use rustc_data_structures::packed::Pu128; |
| ... | ... | @@ -597,6 +600,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 597 | 600 | } |
| 598 | 601 | ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"), |
| 599 | 602 | }; |
| 603 | ||
| 604 | if self.fn_abi.conv == CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) { | |
| 605 | // The return value of an `extern "cmse-nonsecure-entry"` function crosses the | |
| 606 | // secure boundary. Zero padding bytes so information does not leak. | |
| 607 | // | |
| 608 | // This only zeroes "guaranteed" padding. There may be more bytes that are | |
| 609 | // padding for some but not all variants of this type; those are not zeroed. | |
| 610 | // | |
| 611 | // Returning a value with value-dependent padding will instead trigger a lint. | |
| 612 | let ret_layout = self.fn_abi.ret.layout; | |
| 613 | let uninit_ranges = ret_layout.padding_ranges(bx.cx()); | |
| 614 | self.zero_byte_ranges(bx, llslot, ret_layout.size, &uninit_ranges); | |
| 615 | } | |
| 616 | ||
| 600 | 617 | load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi) |
| 601 | 618 | } |
| 602 | 619 | }; |
| ... | ... | @@ -1341,6 +1358,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1341 | 1358 | |
| 1342 | 1359 | self.codegen_argument( |
| 1343 | 1360 | bx, |
| 1361 | fn_abi.conv, | |
| 1344 | 1362 | op, |
| 1345 | 1363 | by_move, |
| 1346 | 1364 | &mut llargs, |
| ... | ... | @@ -1351,6 +1369,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1351 | 1369 | let num_untupled = untuple.map(|tup| { |
| 1352 | 1370 | self.codegen_arguments_untupled( |
| 1353 | 1371 | bx, |
| 1372 | fn_abi.conv, | |
| 1354 | 1373 | &tup.node, |
| 1355 | 1374 | &mut llargs, |
| 1356 | 1375 | &fn_abi.args[first_args.len()..], |
| ... | ... | @@ -1380,6 +1399,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1380 | 1399 | let last_arg = fn_abi.args.last().unwrap(); |
| 1381 | 1400 | self.codegen_argument( |
| 1382 | 1401 | bx, |
| 1402 | fn_abi.conv, | |
| 1383 | 1403 | location, |
| 1384 | 1404 | /* by_move */ false, |
| 1385 | 1405 | &mut llargs, |
| ... | ... | @@ -1696,9 +1716,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1696 | 1716 | } |
| 1697 | 1717 | } |
| 1698 | 1718 | |
| 1719 | fn zero_byte_ranges( | |
| 1720 | &mut self, | |
| 1721 | bx: &mut Bx, | |
| 1722 | ptr: Bx::Value, | |
| 1723 | limit: Size, | |
| 1724 | ranges: &[Range<Size>], | |
| 1725 | ) { | |
| 1726 | let zero = bx.const_u8(0); | |
| 1727 | ||
| 1728 | for range in ranges { | |
| 1729 | let end = cmp::min(range.end, limit); | |
| 1730 | if range.start >= end { | |
| 1731 | continue; | |
| 1732 | } | |
| 1733 | let offset = bx.const_usize(range.start.bytes()); | |
| 1734 | let len = bx.const_usize((end - range.start).bytes()); | |
| 1735 | let ptr = bx.inbounds_ptradd(ptr, offset); | |
| 1736 | bx.memset(ptr, zero, len, Align::ONE, MemFlags::empty()); | |
| 1737 | } | |
| 1738 | } | |
| 1739 | ||
| 1699 | 1740 | fn codegen_argument( |
| 1700 | 1741 | &mut self, |
| 1701 | 1742 | bx: &mut Bx, |
| 1743 | conv: CanonAbi, | |
| 1702 | 1744 | op: OperandRef<'tcx, Bx::Value>, |
| 1703 | 1745 | by_move: bool, |
| 1704 | 1746 | llargs: &mut Vec<Bx::Value>, |
| ... | ... | @@ -1822,6 +1864,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1822 | 1864 | MemFlags::empty(), |
| 1823 | 1865 | None, |
| 1824 | 1866 | ); |
| 1867 | ||
| 1868 | // The arguments of an `extern "cmse-nonsecure-call"` function cross the secure | |
| 1869 | // boundary. Zero padding bytes so information does not leak. | |
| 1870 | // | |
| 1871 | // This only zeroes "guaranteed" padding. There may be more bytes that are | |
| 1872 | // padding for some but not all variants of this type; those are not zeroed. | |
| 1873 | // | |
| 1874 | // Passing an argument with value-dependent padding will instead trigger a lint. | |
| 1875 | if conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) { | |
| 1876 | self.zero_byte_ranges( | |
| 1877 | bx, | |
| 1878 | llscratch, | |
| 1879 | Size::from_bytes(copy_bytes), | |
| 1880 | &arg.layout.padding_ranges(bx.cx()), | |
| 1881 | ); | |
| 1882 | } | |
| 1883 | ||
| 1825 | 1884 | // ...and then load it with the ABI type. |
| 1826 | 1885 | llval = load_cast(bx, cast, llscratch, scratch_align); |
| 1827 | 1886 | bx.lifetime_end(llscratch, scratch_size); |
| ... | ... | @@ -1848,6 +1907,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1848 | 1907 | fn codegen_arguments_untupled( |
| 1849 | 1908 | &mut self, |
| 1850 | 1909 | bx: &mut Bx, |
| 1910 | conv: CanonAbi, | |
| 1851 | 1911 | operand: &mir::Operand<'tcx>, |
| 1852 | 1912 | llargs: &mut Vec<Bx::Value>, |
| 1853 | 1913 | args: &[ArgAbi<'tcx, Ty<'tcx>>], |
| ... | ... | @@ -1867,6 +1927,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1867 | 1927 | let field = bx.load_operand(field_ptr); |
| 1868 | 1928 | self.codegen_argument( |
| 1869 | 1929 | bx, |
| 1930 | conv, | |
| 1870 | 1931 | field, |
| 1871 | 1932 | by_move, |
| 1872 | 1933 | llargs, |
| ... | ... | @@ -1878,7 +1939,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1878 | 1939 | // If the tuple is immediate, the elements are as well. |
| 1879 | 1940 | for i in 0..tuple.layout.fields.count() { |
| 1880 | 1941 | let op = tuple.extract_field(self, bx, i); |
| 1881 | self.codegen_argument(bx, op, by_move, llargs, &args[i], lifetime_ends_after_call); | |
| 1942 | self.codegen_argument( | |
| 1943 | bx, | |
| 1944 | conv, | |
| 1945 | op, | |
| 1946 | by_move, | |
| 1947 | llargs, | |
| 1948 | &args[i], | |
| 1949 | lifetime_ends_after_call, | |
| 1950 | ); | |
| 1882 | 1951 | } |
| 1883 | 1952 | } |
| 1884 | 1953 | tuple.layout.fields.count() |
compiler/rustc_const_eval/src/interpret/validity.rs+3-51| ... | ... | @@ -345,55 +345,7 @@ fn write_path(out: &mut String, path: &[PathElem<'_>]) { |
| 345 | 345 | } |
| 346 | 346 | } |
| 347 | 347 | |
| 348 | /// Represents a set of `Size` values as a sorted list of ranges. | |
| 349 | // These are (offset, length) pairs, and they are sorted and mutually disjoint, | |
| 350 | // and never adjacent (i.e. there's always a gap between two of them). | |
| 351 | #[derive(Debug, Clone)] | |
| 352 | pub struct RangeSet(Vec<(Size, Size)>); | |
| 353 | ||
| 354 | impl RangeSet { | |
| 355 | fn add_range(&mut self, offset: Size, size: Size) { | |
| 356 | if size.bytes() == 0 { | |
| 357 | // No need to track empty ranges. | |
| 358 | return; | |
| 359 | } | |
| 360 | let v = &mut self.0; | |
| 361 | // We scan for a partition point where the left partition is all the elements that end | |
| 362 | // strictly before we start. Those are elements that are too "low" to merge with us. | |
| 363 | let idx = | |
| 364 | v.partition_point(|&(other_offset, other_size)| other_offset + other_size < offset); | |
| 365 | // Now we want to either merge with the first element of the second partition, or insert ourselves before that. | |
| 366 | if let Some(&(other_offset, other_size)) = v.get(idx) | |
| 367 | && offset + size >= other_offset | |
| 368 | { | |
| 369 | // Their end is >= our start (otherwise it would not be in the 2nd partition) and | |
| 370 | // our end is >= their start. This means we can merge the ranges. | |
| 371 | let new_start = other_offset.min(offset); | |
| 372 | let mut new_end = (other_offset + other_size).max(offset + size); | |
| 373 | // We grew to the right, so merge with overlapping/adjacent elements. | |
| 374 | // (We also may have grown to the left, but that can never make us adjacent with | |
| 375 | // anything there since we selected the first such candidate via `partition_point`.) | |
| 376 | let mut scan_right = 1; | |
| 377 | while let Some(&(next_offset, next_size)) = v.get(idx + scan_right) | |
| 378 | && new_end >= next_offset | |
| 379 | { | |
| 380 | // Increase our size to absorb the next element. | |
| 381 | new_end = new_end.max(next_offset + next_size); | |
| 382 | // Look at the next element. | |
| 383 | scan_right += 1; | |
| 384 | } | |
| 385 | // Update the element we grew. | |
| 386 | v[idx] = (new_start, new_end - new_start); | |
| 387 | // Remove the elements we absorbed (if any). | |
| 388 | if scan_right > 1 { | |
| 389 | drop(v.drain((idx + 1)..(idx + scan_right))); | |
| 390 | } | |
| 391 | } else { | |
| 392 | // Insert new element. | |
| 393 | v.insert(idx, (offset, size)); | |
| 394 | } | |
| 395 | } | |
| 396 | } | |
| 348 | pub type RangeSet = rustc_data_structures::range_set::RangeSet<Size>; | |
| 397 | 349 | |
| 398 | 350 | struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> { |
| 399 | 351 | /// The `path` may be pushed to, but the part that is present when a function |
| ... | ... | @@ -1194,7 +1146,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { |
| 1194 | 1146 | assert!(layout.is_sized(), "there are no unsized unions"); |
| 1195 | 1147 | let layout_cx = LayoutCx::new(*ecx.tcx, ecx.typing_env); |
| 1196 | 1148 | return M::cached_union_data_range(ecx, layout.ty, || { |
| 1197 | let mut out = RangeSet(Vec::new()); | |
| 1149 | let mut out = RangeSet::new(); | |
| 1198 | 1150 | union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out); |
| 1199 | 1151 | out |
| 1200 | 1152 | }); |
| ... | ... | @@ -1644,7 +1596,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |
| 1644 | 1596 | ctfe_mode, |
| 1645 | 1597 | ecx, |
| 1646 | 1598 | reset_provenance_and_padding, |
| 1647 | data_bytes: reset_padding.then_some(RangeSet(Vec::new())), | |
| 1599 | data_bytes: reset_padding.then_some(RangeSet::new()), | |
| 1648 | 1600 | may_dangle: start_in_may_dangle, |
| 1649 | 1601 | }; |
| 1650 | 1602 | v.visit_value(val)?; |
compiler/rustc_data_structures/src/lib.rs+1| ... | ... | @@ -68,6 +68,7 @@ pub mod obligation_forest; |
| 68 | 68 | pub mod owned_slice; |
| 69 | 69 | pub mod packed; |
| 70 | 70 | pub mod profiling; |
| 71 | pub mod range_set; | |
| 71 | 72 | pub mod sharded; |
| 72 | 73 | pub mod small_c_str; |
| 73 | 74 | pub mod snapshot_map; |
compiler/rustc_data_structures/src/range_set.rs created+59| ... | ... | @@ -0,0 +1,59 @@ |
| 1 | /// Represents a set of `Size` values as a sorted list of ranges. | |
| 2 | /// | |
| 3 | /// These are (offset, length) pairs, and they are sorted and mutually disjoint, | |
| 4 | /// and never adjacent (i.e. there's always a gap between two of them). | |
| 5 | #[derive(Debug, Clone)] | |
| 6 | pub struct RangeSet<T>(pub Vec<(T, T)>); | |
| 7 | ||
| 8 | impl<T> RangeSet<T> | |
| 9 | where | |
| 10 | T: Copy + Ord + Default, | |
| 11 | T: core::ops::Add<Output = T>, | |
| 12 | T: core::ops::Sub<Output = T>, | |
| 13 | { | |
| 14 | pub fn new() -> Self { | |
| 15 | Self(Vec::new()) | |
| 16 | } | |
| 17 | ||
| 18 | pub fn add_range(&mut self, offset: T, size: T) { | |
| 19 | if size == T::default() { | |
| 20 | // No need to track empty ranges. | |
| 21 | return; | |
| 22 | } | |
| 23 | let v = &mut self.0; | |
| 24 | // We scan for a partition point where the left partition is all the elements that end | |
| 25 | // strictly before we start. Those are elements that are too "low" to merge with us. | |
| 26 | let idx = | |
| 27 | v.partition_point(|&(other_offset, other_size)| other_offset + other_size < offset); | |
| 28 | // Now we want to either merge with the first element of the second partition, or insert ourselves before that. | |
| 29 | if let Some(&(other_offset, other_size)) = v.get(idx) | |
| 30 | && offset + size >= other_offset | |
| 31 | { | |
| 32 | // Their end is >= our start (otherwise it would not be in the 2nd partition) and | |
| 33 | // our end is >= their start. This means we can merge the ranges. | |
| 34 | let new_start = other_offset.min(offset); | |
| 35 | let mut new_end = (other_offset + other_size).max(offset + size); | |
| 36 | // We grew to the right, so merge with overlapping/adjacent elements. | |
| 37 | // (We also may have grown to the left, but that can never make us adjacent with | |
| 38 | // anything there since we selected the first such candidate via `partition_point`.) | |
| 39 | let mut scan_right = 1; | |
| 40 | while let Some(&(next_offset, next_size)) = v.get(idx + scan_right) | |
| 41 | && new_end >= next_offset | |
| 42 | { | |
| 43 | // Increase our size to absorb the next element. | |
| 44 | new_end = new_end.max(next_offset + next_size); | |
| 45 | // Look at the next element. | |
| 46 | scan_right += 1; | |
| 47 | } | |
| 48 | // Update the element we grew. | |
| 49 | v[idx] = (new_start, new_end - new_start); | |
| 50 | // Remove the elements we absorbed (if any). | |
| 51 | if scan_right > 1 { | |
| 52 | drop(v.drain((idx + 1)..(idx + scan_right))); | |
| 53 | } | |
| 54 | } else { | |
| 55 | // Insert new element. | |
| 56 | v.insert(idx, (offset, size)); | |
| 57 | } | |
| 58 | } | |
| 59 | } |
compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs+4-7| ... | ... | @@ -6,7 +6,7 @@ use rustc_errors::{ |
| 6 | 6 | }; |
| 7 | 7 | use rustc_hir::def::{DefKind, Res}; |
| 8 | 8 | use rustc_hir::def_id::DefId; |
| 9 | use rustc_hir::{self as hir, DelegationInfo, GenericArg}; | |
| 9 | use rustc_hir::{self as hir, GenericArg}; | |
| 10 | 10 | use rustc_middle::ty::{ |
| 11 | 11 | self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, |
| 12 | 12 | }; |
| ... | ... | @@ -431,15 +431,12 @@ pub(crate) fn check_generic_arg_count( |
| 431 | 431 | } |
| 432 | 432 | |
| 433 | 433 | let tcx = cx.tcx(); |
| 434 | let parent_def = tcx.hir_get_parent_item(seg.hir_id).def_id; | |
| 435 | 434 | |
| 436 | 435 | // Suppress this warning for delegations as it is compiler generated and lifetimes are |
| 437 | 436 | // propagated while late-bound lifetimes may be present. |
| 438 | let explicit_late_bound = match tcx.hir_opt_delegation_info(parent_def) { | |
| 439 | Some(DelegationInfo { child_seg_id, .. }) if seg.hir_id == *child_seg_id => { | |
| 440 | ExplicitLateBound::No | |
| 441 | } | |
| 442 | _ => prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos), | |
| 437 | let explicit_late_bound = match tcx.hir_is_delegation_child_segment(seg) { | |
| 438 | true => ExplicitLateBound::No, | |
| 439 | false => prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos), | |
| 443 | 440 | }; |
| 444 | 441 | |
| 445 | 442 | let mut invalid_args = vec![]; |
compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs+3-1| ... | ... | @@ -716,6 +716,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 716 | 716 | generic_args: &'a GenericArgs<'tcx>, |
| 717 | 717 | span: Span, |
| 718 | 718 | infer_args: bool, |
| 719 | create_synth_args: bool, | |
| 719 | 720 | incorrect_args: &'a Result<(), GenericArgCountMismatch>, |
| 720 | 721 | } |
| 721 | 722 | |
| ... | ... | @@ -828,7 +829,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 828 | 829 | .instantiate(tcx, preceding_args) |
| 829 | 830 | .skip_norm_wip() |
| 830 | 831 | .into() |
| 831 | } else if synthetic { | |
| 832 | } else if self.create_synth_args && synthetic { | |
| 832 | 833 | Ty::new_param(tcx, param.index, param.name).into() |
| 833 | 834 | } else if infer_args { |
| 834 | 835 | self.lowerer.ty_infer(Some(param), self.span).into() |
| ... | ... | @@ -868,6 +869,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 868 | 869 | span, |
| 869 | 870 | generic_args: segment.args(), |
| 870 | 871 | infer_args: segment.infer_args, |
| 872 | create_synth_args: tcx.hir_is_delegation_child_segment(segment), | |
| 871 | 873 | incorrect_args: &arg_count.correct, |
| 872 | 874 | }; |
| 873 | 875 |
compiler/rustc_hir_typeck/src/expr.rs+3| ... | ... | @@ -3159,6 +3159,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 3159 | 3159 | |
| 3160 | 3160 | fn suggest_first_deref_field(&self, err: &mut Diag<'_>, base: &hir::Expr<'_>, field: Ident) { |
| 3161 | 3161 | err.span_label(field.span, "unknown field"); |
| 3162 | if base.span.from_expansion() || field.span.from_expansion() { | |
| 3163 | return; | |
| 3164 | } | |
| 3162 | 3165 | let val = if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) |
| 3163 | 3166 | && base.len() < 20 |
| 3164 | 3167 | { |
compiler/rustc_interface/src/tests.rs+6-6| ... | ... | @@ -13,11 +13,11 @@ use rustc_session::config::{ |
| 13 | 13 | AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CodegenRetagOptions, CoverageLevel, |
| 14 | 14 | CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, |
| 15 | 15 | Externs, FmtDebug, FunctionReturn, IncrementalStateAssertion, InliningThreshold, Input, |
| 16 | InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, | |
| 17 | MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName, OutputType, OutputTypes, | |
| 18 | PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, | |
| 19 | SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, build_configuration, | |
| 20 | build_session_options, rustc_optgroups, | |
| 16 | InstrumentCoverage, InstrumentMcount, InstrumentXRay, LinkSelfContained, LinkerPluginLto, | |
| 17 | LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName, | |
| 18 | OutputType, OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius, | |
| 19 | ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, | |
| 20 | build_configuration, build_session_options, rustc_optgroups, | |
| 21 | 21 | }; |
| 22 | 22 | use rustc_session::lint::Level; |
| 23 | 23 | use rustc_session::search_paths::SearchPath; |
| ... | ... | @@ -834,7 +834,7 @@ fn test_unstable_options_tracking_hash() { |
| 834 | 834 | tracked!(inline_mir, Some(true)); |
| 835 | 835 | tracked!(inline_mir_hint_threshold, Some(123)); |
| 836 | 836 | tracked!(inline_mir_threshold, Some(123)); |
| 837 | tracked!(instrument_mcount, true); | |
| 837 | tracked!(instrument_mcount, InstrumentMcount::Mcount); | |
| 838 | 838 | tracked!(instrument_xray, Some(InstrumentXRay::default())); |
| 839 | 839 | tracked!(link_directives, false); |
| 840 | 840 | tracked!(link_only, true); |
compiler/rustc_middle/src/hir/map.rs+7| ... | ... | @@ -879,6 +879,13 @@ impl<'tcx> TyCtxt<'tcx> { |
| 879 | 879 | self.hir_opt_delegation_info(delegation_id).expect("processing delegation") |
| 880 | 880 | } |
| 881 | 881 | |
| 882 | pub fn hir_is_delegation_child_segment(self, segment: &PathSegment<'_>) -> bool { | |
| 883 | let parent_def = self.hir_get_parent_item(segment.hir_id).def_id; | |
| 884 | ||
| 885 | self.hir_opt_delegation_info(parent_def) | |
| 886 | .is_some_and(|info| info.child_seg_id == segment.hir_id) | |
| 887 | } | |
| 888 | ||
| 882 | 889 | #[inline] |
| 883 | 890 | fn hir_opt_ident(self, id: HirId) -> Option<Ident> { |
| 884 | 891 | match self.hir_node(id) { |
compiler/rustc_passes/src/check_attr.rs+15-8| ... | ... | @@ -24,8 +24,9 @@ use rustc_hir::def::DefKind; |
| 24 | 24 | use rustc_hir::def_id::LocalModDefId; |
| 25 | 25 | use rustc_hir::intravisit::{self, Visitor}; |
| 26 | 26 | use rustc_hir::{ |
| 27 | self as hir, Attribute, CRATE_HIR_ID, Constness, FnSig, ForeignItem, GenericParamKind, HirId, | |
| 28 | Item, ItemKind, MethodKind, Node, ParamName, Target, TraitItem, find_attr, | |
| 27 | self as hir, Attribute, CRATE_HIR_ID, Constness, FnSig, ForeignItem, GenericParam, | |
| 28 | GenericParamKind, HirId, Item, ItemKind, MethodKind, Node, ParamName, Target, TraitItem, | |
| 29 | find_attr, | |
| 29 | 30 | }; |
| 30 | 31 | use rustc_macros::Diagnostic; |
| 31 | 32 | use rustc_middle::hir::nested_filter; |
| ... | ... | @@ -1121,12 +1122,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { |
| 1121 | 1122 | |
| 1122 | 1123 | /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. |
| 1123 | 1124 | fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) { |
| 1124 | if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) | |
| 1125 | && matches!( | |
| 1126 | param.kind, | |
| 1127 | hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } | |
| 1128 | ) | |
| 1129 | && matches!(param.source, hir::GenericParamSource::Generics) | |
| 1125 | let hir::Node::GenericParam( | |
| 1126 | param @ GenericParam { | |
| 1127 | kind: hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. }, | |
| 1128 | .. | |
| 1129 | }, | |
| 1130 | ) = self.tcx.hir_node(hir_id) | |
| 1131 | else { | |
| 1132 | self.dcx().delayed_bug("Checked in attr parser"); | |
| 1133 | return; | |
| 1134 | }; | |
| 1135 | ||
| 1136 | if matches!(param.source, hir::GenericParamSource::Generics) | |
| 1130 | 1137 | && let parent_hir_id = self.tcx.parent_hir_id(hir_id) |
| 1131 | 1138 | && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id) |
| 1132 | 1139 | && let hir::ItemKind::Impl(impl_) = item.kind |
compiler/rustc_session/src/config.rs+17-5| ... | ... | @@ -255,6 +255,17 @@ pub enum AnnotateMoves { |
| 255 | 255 | Enabled(Option<u64>), |
| 256 | 256 | } |
| 257 | 257 | |
| 258 | /// The different settings that the `-Z Instrument-mcount` flag can have. | |
| 259 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | |
| 260 | pub enum InstrumentMcount { | |
| 261 | /// `-Z instrument-mcount=no` | |
| 262 | Disabled, | |
| 263 | /// `-Z instrument-mcount=yes` | |
| 264 | Mcount, | |
| 265 | /// `-Z instrument-mcount=fentry` | |
| 266 | Fentry, | |
| 267 | } | |
| 268 | ||
| 258 | 269 | /// Settings for `-Z instrument-xray` flag. |
| 259 | 270 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] |
| 260 | 271 | pub struct InstrumentXRay { |
| ... | ... | @@ -3085,11 +3096,11 @@ pub(crate) mod dep_tracking { |
| 3085 | 3096 | use super::{ |
| 3086 | 3097 | AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CodegenRetagOptions, |
| 3087 | 3098 | CoverageOptions, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, |
| 3088 | FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, | |
| 3089 | LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, | |
| 3090 | OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, ResolveDocLinks, | |
| 3091 | SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, | |
| 3092 | WasiExecModel, | |
| 3099 | FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentMcount, InstrumentXRay, | |
| 3100 | LinkerPluginLto, LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, | |
| 3101 | OptLevel, OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, | |
| 3102 | ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, | |
| 3103 | SymbolManglingVersion, WasiExecModel, | |
| 3093 | 3104 | }; |
| 3094 | 3105 | use crate::lint; |
| 3095 | 3106 | use crate::utils::NativeLib; |
| ... | ... | @@ -3151,6 +3162,7 @@ pub(crate) mod dep_tracking { |
| 3151 | 3162 | TlsModel, |
| 3152 | 3163 | InstrumentCoverage, |
| 3153 | 3164 | CoverageOptions, |
| 3165 | InstrumentMcount, | |
| 3154 | 3166 | InstrumentXRay, |
| 3155 | 3167 | CrateType, |
| 3156 | 3168 | MergeFunctions, |
compiler/rustc_session/src/options.rs+16-1| ... | ... | @@ -804,6 +804,8 @@ mod desc { |
| 804 | 804 | pub(crate) const parse_coverage_options: &str = "`block` | `branch` | `condition`"; |
| 805 | 805 | pub(crate) const parse_codegen_retag_options: &str = |
| 806 | 806 | "either no value or a comma-separated list of settings: `no-precise-im`, `no-precise-pin`"; |
| 807 | pub(crate) const parse_instrument_mcount: &str = | |
| 808 | "either a boolean (`yes`, `no`, `on`, `off`, etc), or `fentry` on supported targets."; | |
| 807 | 809 | pub(crate) const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; |
| 808 | 810 | pub(crate) const parse_unpretty: &str = "`string` or `string=string`"; |
| 809 | 811 | pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; |
| ... | ... | @@ -1583,6 +1585,19 @@ pub mod parse { |
| 1583 | 1585 | true |
| 1584 | 1586 | } |
| 1585 | 1587 | |
| 1588 | pub(crate) fn parse_instrument_mcount(slot: &mut InstrumentMcount, v: Option<&str>) -> bool { | |
| 1589 | let mut use_mcount = false; | |
| 1590 | if parse_bool(&mut use_mcount, v) { | |
| 1591 | *slot = if use_mcount { InstrumentMcount::Mcount } else { InstrumentMcount::Disabled }; | |
| 1592 | true | |
| 1593 | } else if let Some("fentry") = v { | |
| 1594 | *slot = InstrumentMcount::Fentry; | |
| 1595 | true | |
| 1596 | } else { | |
| 1597 | false | |
| 1598 | } | |
| 1599 | } | |
| 1600 | ||
| 1586 | 1601 | pub(crate) fn parse_instrument_xray( |
| 1587 | 1602 | slot: &mut Option<InstrumentXRay>, |
| 1588 | 1603 | v: Option<&str>, |
| ... | ... | @@ -2453,7 +2468,7 @@ options! { |
| 2453 | 2468 | "a default MIR inlining threshold (default: 50)"), |
| 2454 | 2469 | input_stats: bool = (false, parse_bool, [UNTRACKED], |
| 2455 | 2470 | "print some statistics about AST and HIR (default: no)"), |
| 2456 | instrument_mcount: bool = (false, parse_bool, [TRACKED], | |
| 2471 | instrument_mcount: InstrumentMcount = (InstrumentMcount::Disabled, parse_instrument_mcount, [TRACKED], | |
| 2457 | 2472 | "insert function instrument code for mcount-based tracing (default: no)"), |
| 2458 | 2473 | instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED], |
| 2459 | 2474 | "insert function instrument code for XRay-based tracing (default: no) |
compiler/rustc_session/src/session.rs+7-1| ... | ... | @@ -38,7 +38,7 @@ use crate::code_stats::CodeStats; |
| 38 | 38 | pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; |
| 39 | 39 | use crate::config::{ |
| 40 | 40 | self, Cfg, CheckCfg, CoverageLevel, CoverageOptions, CrateType, DebugInfo, ErrorOutputType, |
| 41 | FunctionReturn, Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, | |
| 41 | FunctionReturn, Input, InstrumentCoverage, InstrumentMcount, OptLevel, OutFileName, OutputType, | |
| 42 | 42 | SwitchWithOptPath, |
| 43 | 43 | }; |
| 44 | 44 | use crate::filesearch::FileSearch; |
| ... | ... | @@ -1340,6 +1340,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) { |
| 1340 | 1340 | } |
| 1341 | 1341 | } |
| 1342 | 1342 | |
| 1343 | if sess.opts.unstable_opts.instrument_mcount == InstrumentMcount::Fentry | |
| 1344 | && !sess.target.options.supports_fentry | |
| 1345 | { | |
| 1346 | sess.dcx().emit_err(errors::InstrumentationNotSupported { us: "fentry".to_string() }); | |
| 1347 | } | |
| 1348 | ||
| 1343 | 1349 | if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray { |
| 1344 | 1350 | sess.dcx().emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() }); |
| 1345 | 1351 | } |
compiler/rustc_target/src/spec/json.rs+3| ... | ... | @@ -223,6 +223,7 @@ impl Target { |
| 223 | 223 | forward!(supports_stack_protector); |
| 224 | 224 | forward!(small_data_threshold_support); |
| 225 | 225 | forward!(entry_name); |
| 226 | forward!(supports_fentry); | |
| 226 | 227 | forward!(supports_xray); |
| 227 | 228 | |
| 228 | 229 | // we're going to run `update_from_cli`, but that won't change the target's AbiMap |
| ... | ... | @@ -407,6 +408,7 @@ impl ToJson for Target { |
| 407 | 408 | target_option_val!(small_data_threshold_support); |
| 408 | 409 | target_option_val!(entry_name); |
| 409 | 410 | target_option_val!(entry_abi); |
| 411 | target_option_val!(supports_fentry); | |
| 410 | 412 | target_option_val!(supports_xray); |
| 411 | 413 | |
| 412 | 414 | // Serializing `-Clink-self-contained` needs a dynamic key to support the |
| ... | ... | @@ -626,6 +628,7 @@ struct TargetSpecJson { |
| 626 | 628 | supports_stack_protector: Option<bool>, |
| 627 | 629 | small_data_threshold_support: Option<SmallDataThresholdSupport>, |
| 628 | 630 | entry_name: Option<StaticCow<str>>, |
| 631 | supports_fentry: Option<bool>, | |
| 629 | 632 | supports_xray: Option<bool>, |
| 630 | 633 | entry_abi: Option<ExternAbiWrapper>, |
| 631 | 634 | } |
compiler/rustc_target/src/spec/mod.rs+4| ... | ... | @@ -2688,6 +2688,9 @@ pub struct TargetOptions { |
| 2688 | 2688 | /// Default value is `CanonAbi::C` |
| 2689 | 2689 | pub entry_abi: CanonAbi, |
| 2690 | 2690 | |
| 2691 | /// Whether the target supports fentry instrumentation. | |
| 2692 | pub supports_fentry: bool, | |
| 2693 | ||
| 2691 | 2694 | /// Whether the target supports XRay instrumentation. |
| 2692 | 2695 | pub supports_xray: bool, |
| 2693 | 2696 | |
| ... | ... | @@ -2929,6 +2932,7 @@ impl Default for TargetOptions { |
| 2929 | 2932 | supports_stack_protector: true, |
| 2930 | 2933 | entry_name: "main".into(), |
| 2931 | 2934 | entry_abi: CanonAbi::C, |
| 2935 | supports_fentry: false, | |
| 2932 | 2936 | supports_xray: false, |
| 2933 | 2937 | default_address_space: rustc_abi::AddressSpace::ZERO, |
| 2934 | 2938 | small_data_threshold_support: SmallDataThresholdSupport::DefaultForArch, |
compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs+1| ... | ... | @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { |
| 22 | 22 | base.supported_sanitizers = SanitizerSet::ADDRESS; |
| 23 | 23 | base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); |
| 24 | 24 | base.stack_probes = StackProbeType::Inline; |
| 25 | base.supports_fentry = true; | |
| 25 | 26 | |
| 26 | 27 | Target { |
| 27 | 28 | llvm_target: "i686-unknown-linux-gnu".into(), |
compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs+1| ... | ... | @@ -12,6 +12,7 @@ pub(crate) fn target() -> Target { |
| 12 | 12 | base.max_atomic_width = Some(64); |
| 13 | 13 | base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-Wl,-melf_i386"]); |
| 14 | 14 | base.stack_probes = StackProbeType::Inline; |
| 15 | base.supports_fentry = true; | |
| 15 | 16 | // FIXME(compiler-team#422): musl targets should be dynamically linked by default. |
| 16 | 17 | base.crt_static_default = true; |
| 17 | 18 |
compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs+1| ... | ... | @@ -12,6 +12,7 @@ pub(crate) fn target() -> Target { |
| 12 | 12 | base.stack_probes = StackProbeType::Inline; |
| 13 | 13 | base.supported_sanitizers = |
| 14 | 14 | SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; |
| 15 | base.supports_fentry = true; | |
| 15 | 16 | |
| 16 | 17 | Target { |
| 17 | 18 | llvm_target: "s390x-unknown-linux-gnu".into(), |
compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs+1| ... | ... | @@ -13,6 +13,7 @@ pub(crate) fn target() -> Target { |
| 13 | 13 | base.stack_probes = StackProbeType::Inline; |
| 14 | 14 | base.supported_sanitizers = |
| 15 | 15 | SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; |
| 16 | base.supports_fentry = true; | |
| 16 | 17 | |
| 17 | 18 | Target { |
| 18 | 19 | llvm_target: "s390x-unknown-linux-musl".into(), |
compiler/rustc_target/src/spec/targets/s390x_unknown_none_softfloat.rs+1| ... | ... | @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { |
| 20 | 20 | rustc_abi: Some(RustcAbi::Softfloat), |
| 21 | 21 | stack_probes: StackProbeType::Inline, |
| 22 | 22 | supported_sanitizers: SanitizerSet::KERNELADDRESS, |
| 23 | supports_fentry: true, | |
| 23 | 24 | ..Default::default() |
| 24 | 25 | }; |
| 25 | 26 |
compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs+1| ... | ... | @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { |
| 19 | 19 | | SanitizerSet::SAFESTACK |
| 20 | 20 | | SanitizerSet::THREAD |
| 21 | 21 | | SanitizerSet::REALTIME; |
| 22 | base.supports_fentry = true; | |
| 22 | 23 | base.supports_xray = true; |
| 23 | 24 | |
| 24 | 25 | Target { |
compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs+1| ... | ... | @@ -15,6 +15,7 @@ pub(crate) fn target() -> Target { |
| 15 | 15 | | SanitizerSet::LEAK |
| 16 | 16 | | SanitizerSet::MEMORY |
| 17 | 17 | | SanitizerSet::THREAD; |
| 18 | base.supports_fentry = true; | |
| 18 | 19 | base.supports_xray = true; |
| 19 | 20 | // FIXME(compiler-team#422): musl targets should be dynamically linked by default. |
| 20 | 21 | base.crt_static_default = true; |
compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs+1| ... | ... | @@ -10,6 +10,7 @@ pub(crate) fn target() -> Target { |
| 10 | 10 | base.linker_flavor = LinkerFlavor::Gnu(Cc::No, Lld::Yes); |
| 11 | 11 | base.linker = Some("rust-lld".into()); |
| 12 | 12 | base.panic_strategy = PanicStrategy::Abort; |
| 13 | base.supports_fentry = true; | |
| 13 | 14 | |
| 14 | 15 | Target { |
| 15 | 16 | llvm_target: "x86_64-unknown-linux-none".into(), |
src/doc/unstable-book/src/compiler-flags/instrument-mcount.md created+143| ... | ... | @@ -0,0 +1,143 @@ |
| 1 | # `instrument-mcount` | |
| 2 | ||
| 3 | Insert calls to a counting function at the entry of each function. Traditionally, the name of this function was | |
| 4 | mcount, but the exact name may vary depending on target and option usage. | |
| 5 | ||
| 6 | The counting function is a special function which does not typically follow a target's ABI. It generally takes | |
| 7 | two arguments, the address of the calling function and the address of the called function. It was intially used | |
| 8 | to profile applications, but has expanded to other usages (for example [ftrace on Linux](https://docs.kernel.org/trace/ftrace.html)). | |
| 9 | ||
| 10 | Supported options: | |
| 11 | ||
| 12 | - `no`, `n`, `off`: Do no enable instrumentation. The default option. This requires, and enables frame pointer generation. | |
| 13 | - `yes`, `y`, `on`: Enable mcount based function instrumentation. | |
| 14 | - `fentry`: Enable fentry based function instrument, where supported. The calling conventions for this are different than mcount, with less overhead, and no frame pointer requirements. This counting function is always named `__fentry__`. This is only available on x86 and s390x targets. | |
| 15 | ||
| 16 | |target |mcount function|supports fentry|ABI notes| | |
| 17 | |--- |--- |--- |--- | | |
| 18 | |aarch64-apple-darwin | `\u{1}mcount` | | | | |
| 19 | |aarch64-pc-windows-msvc | `mcount` | | | | |
| 20 | |aarch64-unknown-linux-gnu| `_mcount` | | | | |
| 21 | |i686-pc-windows-msvc | `mcount` | x| | | |
| 22 | |i686-unknown-linux-gnu | `mcount` | x| | | |
| 23 | |x86_64-pc-windows-gnu | `_mcount` | x| | | |
| 24 | |x86_64-pc-windows-msvc | `mcount` | x| | | |
| 25 | |x86_64-unknown-linux-gnu | `mcount` | x| 1| | |
| 26 | ||
| 27 | On arm eabi targets, the mcount function is usually named `__gnu_mcount_nc`, though some targets may use different names. Implementers of counting function should consult the target specific documentation for quirks of each ABI function. | |
| 28 | ||
| 29 | 1. On x86-64, mcount and fentry must preserve the argument registers `rax`, `rcx`, `rdx`, `rsi`, `rdi`, `r8`, `r9`. When using fentry, the stack pointer `rsp` may need aligned to meet ABI requirements. | |
| 30 | ||
| 31 | ## Implementing custom counting functions | |
| 32 | ||
| 33 | In essence, this is implementing the function `fn mcount(caller: *const std::ffi::c_void, callee: *const std::ffi::c_void)`. The calling convention for mcount follows its own ABI, which isn't usually the standard ABI for the target, but is enforced by preexisting convention. | |
| 34 | ||
| 35 | A trivial example on x86_64-unknown-linux-gnu looks something like the following. The `#[instrument_fn]` attribute can be used to disable profiling to simplify writing counting functions, but implementors must be very careful when calling other functions (or closures which fail to inline) as they may also call mcount. | |
| 36 | ||
| 37 | The following example can be compiled with `-Zinstrument-mcount=yes` or `-Zinstrument-mcount=fentry` on an x86_64-unknown-linux-gnu target. It is also acceptable to link objects with different usages of `-Zinstrument-mcount`, however doing so will require implementing both `__fentry__` and `mcount` on targets which support both. | |
| 38 | ||
| 39 | ```rust | |
| 40 | #![feature(instrument_fn)] | |
| 41 | #![feature(abi_custom)] | |
| 42 | ||
| 43 | fn main() { | |
| 44 | // Ensure all the early startup occurs before attempting to call this trivial, single-threaded | |
| 45 | // counting function. | |
| 46 | unsafe { | |
| 47 | PROFILING_ENABLED = true; | |
| 48 | } | |
| 49 | println!("main() called"); | |
| 50 | unsafe { | |
| 51 | PROFILING_ENABLED = false; | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 55 | // This example is not threadsafe. | |
| 56 | pub static mut IN_MCOUNT: isize = 0; | |
| 57 | pub static mut PROFILING_ENABLED: bool = false; | |
| 58 | ||
| 59 | #[unsafe(no_mangle)] | |
| 60 | #[instrument_fn = "off"] | |
| 61 | unsafe extern "C" fn __count_fn(caller: u64, callee: u64) { | |
| 62 | unsafe { | |
| 63 | if IN_MCOUNT == 0 && PROFILING_ENABLED { | |
| 64 | IN_MCOUNT += 1; | |
| 65 | { | |
| 66 | println!("mcount: call from 0x{caller:x} to 0x{callee:x}"); | |
| 67 | } | |
| 68 | IN_MCOUNT -= 1; | |
| 69 | } | |
| 70 | } | |
| 71 | } | |
| 72 | ||
| 73 | // Define a custom mcount function. This may partially or fully override the glibc | |
| 74 | // implementation depending on linker options. | |
| 75 | #[unsafe(naked)] | |
| 76 | #[unsafe(no_mangle)] | |
| 77 | #[cfg(all(target_os = "linux", target_arch = "x86_64"))] | |
| 78 | unsafe extern "custom" fn mcount() { | |
| 79 | core::arch::naked_asm!( | |
| 80 | // A simplified version based on the glibc x86-64 mcount wrapper. | |
| 81 | // Save register arguments to the stack, and call the mcount above. | |
| 82 | "push rax", | |
| 83 | "push rcx", | |
| 84 | "push rdx", | |
| 85 | "push rsi", | |
| 86 | "push rdi", | |
| 87 | "push r8", | |
| 88 | "push r9", | |
| 89 | "mov rsi, 56[rsp]", | |
| 90 | "mov rdi, 8[rbp]", | |
| 91 | "call __count_fn", | |
| 92 | "pop r9", | |
| 93 | "pop r8", | |
| 94 | "pop rdi", | |
| 95 | "pop rsi", | |
| 96 | "pop rdx", | |
| 97 | "pop rcx", | |
| 98 | "pop rax", | |
| 99 | "ret", | |
| 100 | ) | |
| 101 | } | |
| 102 | ||
| 103 | // Supply a custom __fentry__ instead of glibc's. This has the same linker | |
| 104 | // restrictions as noted with mcount, but does not require a frame pointer. | |
| 105 | #[unsafe(naked)] | |
| 106 | #[unsafe(no_mangle)] | |
| 107 | #[cfg(all(target_os = "linux", target_arch = "x86_64"))] | |
| 108 | unsafe extern "custom" fn __fentry__() { | |
| 109 | core::arch::naked_asm!( | |
| 110 | // __fentry__ is called before any other prologue actions, be careful | |
| 111 | // with stack alignment. The stack slots look something like: | |
| 112 | // [...] | |
| 113 | // [caller return address] | |
| 114 | // [callee return address] <- top of stack | |
| 115 | "sub rsp, 8", | |
| 116 | "push rax", | |
| 117 | "push rcx", | |
| 118 | "push rdx", | |
| 119 | "push rsi", | |
| 120 | "push rdi", | |
| 121 | "push r8", | |
| 122 | "push r9", | |
| 123 | "mov rsi, 64[rsp]", | |
| 124 | "mov rdi, 72[rsp]", | |
| 125 | "call __count_fn", | |
| 126 | "pop r9", | |
| 127 | "pop r8", | |
| 128 | "pop rdi", | |
| 129 | "pop rsi", | |
| 130 | "pop rdx", | |
| 131 | "pop rcx", | |
| 132 | "pop rax", | |
| 133 | "add rsp, 8", | |
| 134 | "ret", | |
| 135 | ) | |
| 136 | } | |
| 137 | ``` | |
| 138 | ||
| 139 | When run, the above program should produce output similar to: | |
| 140 | ```txt | |
| 141 | mcount: call from 0x5614c97d778a to 0x5614c97d76e5 | |
| 142 | main() called | |
| 143 | ``` |
src/llvm-project+1-1| ... | ... | @@ -1 +1 @@ |
| 1 | Subproject commit ec9ab9d68bf7a0e86b2ddf3c0e6e3c4620e02961 | |
| 1 | Subproject commit 3c3f13025bf9f99bb2a757eb37dad4f09e7d6c36 |
tests/assembly-llvm/cmse-clear-padding.rs created+204| ... | ... | @@ -0,0 +1,204 @@ |
| 1 | //@ add-minicore | |
| 2 | //@ min-llvm-version: 22 | |
| 3 | //@ assembly-output: emit-asm | |
| 4 | //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Copt-level=1 | |
| 5 | //@ needs-llvm-components: arm | |
| 6 | #![crate_type = "lib"] | |
| 7 | #![feature(abi_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items)] | |
| 8 | #![no_core] | |
| 9 | ||
| 10 | // Test that padding and other uninitialized bytes are zeroed when a value crosses the secure | |
| 11 | // boundary. | |
| 12 | // | |
| 13 | // The assembly uses the following instructions for clearing the bits: | |
| 14 | // | |
| 15 | // - `uxtb` clears bits 8..32 | |
| 16 | // - `uxth` clears bits 16..32 | |
| 17 | // - `bic` clears bits based on a mask | |
| 18 | // | |
| 19 | // When passing arguments the current implementation of the C ABI already clears padding sometimes, | |
| 20 | // but it's not something that can be relied on. | |
| 21 | ||
| 22 | extern crate minicore; | |
| 23 | use minicore::*; | |
| 24 | ||
| 25 | #[repr(C)] | |
| 26 | struct InnerPadding { | |
| 27 | a: u8, | |
| 28 | b: u16, | |
| 29 | } | |
| 30 | ||
| 31 | // CHECK-LABEL: c_ret_with_inner_padding: | |
| 32 | // CHECK: mov r7, sp | |
| 33 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 34 | #[no_mangle] | |
| 35 | extern "C" fn c_ret_with_inner_padding(a: u8, b: u16) -> InnerPadding { | |
| 36 | InnerPadding { a, b } | |
| 37 | } | |
| 38 | ||
| 39 | // CHECK-LABEL: cmse_ret_with_inner_padding: | |
| 40 | // CHECK: mov r7, sp | |
| 41 | // CHECK-NEXT: uxtb r0, r0 | |
| 42 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 43 | #[no_mangle] | |
| 44 | extern "cmse-nonsecure-entry" fn cmse_ret_with_inner_padding(a: u8, b: u16) -> InnerPadding { | |
| 45 | InnerPadding { a, b } | |
| 46 | } | |
| 47 | ||
| 48 | // CHECK-LABEL: c_call_with_inner_padding: | |
| 49 | // CHECK: mov r7, sp | |
| 50 | // CHECK-NEXT: mov r2, r0 | |
| 51 | // CHECK-NEXT: bic r0, r1, #65280 | |
| 52 | // CHECK-NEXT: pop.w {r7, lr} | |
| 53 | #[no_mangle] | |
| 54 | extern "C" fn c_call_with_inner_padding(f: unsafe extern "C" fn(InnerPadding), x: InnerPadding) { | |
| 55 | unsafe { f(x) } | |
| 56 | } | |
| 57 | ||
| 58 | // CHECK-LABEL: cmse_call_with_inner_padding: | |
| 59 | // CHECK: mov r7, sp | |
| 60 | // CHECK-NEXT: mov r2, r0 | |
| 61 | // CHECK-NEXT: bic r0, r1, #65280 | |
| 62 | // CHECK-NEXT: push.w {r4, r5, r6, r7, r8, r9, r10, r11} | |
| 63 | #[no_mangle] | |
| 64 | extern "C" fn cmse_call_with_inner_padding( | |
| 65 | f: unsafe extern "cmse-nonsecure-call" fn(InnerPadding), | |
| 66 | x: InnerPadding, | |
| 67 | ) { | |
| 68 | unsafe { f(x) } | |
| 69 | } | |
| 70 | ||
| 71 | #[repr(C)] | |
| 72 | struct TrailingPadding { | |
| 73 | a: u16, | |
| 74 | b: u8, | |
| 75 | } | |
| 76 | ||
| 77 | // CHECK-LABEL: c_ret_with_trailing_padding: | |
| 78 | // CHECK: mov r7, sp | |
| 79 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 80 | #[no_mangle] | |
| 81 | extern "C" fn c_ret_with_trailing_padding(a: u16, b: u8) -> TrailingPadding { | |
| 82 | TrailingPadding { a, b } | |
| 83 | } | |
| 84 | ||
| 85 | // CHECK-LABEL: cmse_ret_with_trailing_padding: | |
| 86 | // CHECK: mov r7, sp | |
| 87 | // CHECK-NEXT: uxtb r1, r1 | |
| 88 | // CHECK-NEXT: uxth r0, r0 | |
| 89 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 90 | #[no_mangle] | |
| 91 | extern "cmse-nonsecure-entry" fn cmse_ret_with_trailing_padding(a: u16, b: u8) -> TrailingPadding { | |
| 92 | TrailingPadding { a, b } | |
| 93 | } | |
| 94 | ||
| 95 | // CHECK-LABEL: c_call_with_trailing_padding: | |
| 96 | // CHECK: mov r7, sp | |
| 97 | // CHECK-NEXT: mov r2, r0 | |
| 98 | // CHECK-NEXT: bic r0, r1, #-16777216 | |
| 99 | // CHECK-NEXT: pop.w {r7, lr} | |
| 100 | #[no_mangle] | |
| 101 | extern "C" fn c_call_with_trailing_padding( | |
| 102 | f: unsafe extern "C" fn(TrailingPadding), | |
| 103 | x: TrailingPadding, | |
| 104 | ) { | |
| 105 | unsafe { f(x) } | |
| 106 | } | |
| 107 | ||
| 108 | // CHECK-LABEL: cmse_call_with_trailing_padding: | |
| 109 | // CHECK: mov r7, sp | |
| 110 | // CHECK-NEXT: mov r2, r0 | |
| 111 | // CHECK-NEXT: bic r0, r1, #-16777216 | |
| 112 | // CHECK-NEXT: push.w {r4, r5, r6, r7, r8, r9, r10, r11} | |
| 113 | #[no_mangle] | |
| 114 | extern "C" fn cmse_call_with_trailing_padding( | |
| 115 | f: unsafe extern "cmse-nonsecure-call" fn(TrailingPadding), | |
| 116 | x: TrailingPadding, | |
| 117 | ) { | |
| 118 | unsafe { f(x) } | |
| 119 | } | |
| 120 | ||
| 121 | #[repr(C, align(2))] | |
| 122 | struct WideU8 { | |
| 123 | a: u8, | |
| 124 | } | |
| 125 | ||
| 126 | // CHECK-LABEL: c_ret_with_wide_u8: | |
| 127 | // CHECK: mov r7, sp | |
| 128 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 129 | #[no_mangle] | |
| 130 | extern "C" fn c_ret_with_wide_u8(a: u8, b: u8) -> [WideU8; 2] { | |
| 131 | [WideU8 { a }, WideU8 { a: b }] | |
| 132 | } | |
| 133 | ||
| 134 | // CHECK-LABEL: cmse_ret_with_wide_u8: | |
| 135 | // CHECK: mov r7, sp | |
| 136 | // CHECK-NEXT: uxtb r1, r1 | |
| 137 | // CHECK-NEXT: uxtb r0, r0 | |
| 138 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 139 | #[no_mangle] | |
| 140 | extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8(a: u8, b: u8) -> [WideU8; 2] { | |
| 141 | [WideU8 { a }, WideU8 { a: b }] | |
| 142 | } | |
| 143 | ||
| 144 | // CHECK-LABEL: c_call_with_inner_wide_u8: | |
| 145 | // CHECK: push {r7, lr} | |
| 146 | // CHECK-NEXT: .setfp r7, sp | |
| 147 | // CHECK-NEXT: mov r7, sp | |
| 148 | // CHECK-NEXT: mov lr, r3 | |
| 149 | // CHECK-NEXT: mov r12, r0 | |
| 150 | // CHECK-NEXT: ldr r3, [r7, #8] | |
| 151 | // CHECK-NEXT: mov r0, r1 | |
| 152 | // CHECK-NEXT: mov r1, r2 | |
| 153 | // CHECK-NEXT: mov r2, lr | |
| 154 | // CHECK-NEXT: pop.w {r7, lr} | |
| 155 | // CHECK-NEXT: bx r12 | |
| 156 | #[no_mangle] | |
| 157 | extern "C" fn c_call_with_inner_wide_u8(f: unsafe extern "C" fn([WideU8; 8]), x: [WideU8; 8]) { | |
| 158 | unsafe { f(x) } | |
| 159 | } | |
| 160 | ||
| 161 | // CHECK-LABEL: cmse_call_with_inner_wide_u8: | |
| 162 | // CHECK: push {r7, lr} | |
| 163 | // CHECK-NEXT: .setfp r7, sp | |
| 164 | // CHECK-NEXT: mov r7, sp | |
| 165 | // CHECK-NEXT: mov r12, r0 | |
| 166 | // CHECK-NEXT: bic r0, r1, #-16711936 | |
| 167 | // CHECK-NEXT: bic r1, r2, #-16711936 | |
| 168 | // CHECK-NEXT: bic r2, r3, #-16711936 | |
| 169 | // CHECK-NEXT: ldr r3, [r7, #8] | |
| 170 | // CHECK-NEXT: bic r3, r3, #-16711936 | |
| 171 | // CHECK-NEXT: push.w {r4, r5, r6, r7, r8, r9, r10, r11} | |
| 172 | #[no_mangle] | |
| 173 | extern "C" fn cmse_call_with_inner_wide_u8( | |
| 174 | f: unsafe extern "cmse-nonsecure-call" fn([WideU8; 8]), | |
| 175 | x: [WideU8; 8], | |
| 176 | ) { | |
| 177 | unsafe { f(x) } | |
| 178 | } | |
| 179 | ||
| 180 | // CHECK-LABEL: cmse_ret_with_wide_u8_uninit: | |
| 181 | // CHECK: mov r7, sp | |
| 182 | // CHECK-NEXT: uxtb r0, r0 | |
| 183 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 184 | // CHECK-NEXT: bic r0, r0, #-16711936 | |
| 185 | #[no_mangle] | |
| 186 | extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8_uninit( | |
| 187 | a: u16, | |
| 188 | b: u16, | |
| 189 | ) -> [MaybeUninit<WideU8>; 2] { | |
| 190 | unsafe { [mem::transmute(a), mem::transmute(b)] } | |
| 191 | } | |
| 192 | ||
| 193 | // CHECK-LABEL: cmse_ret_with_wide_u8_uninit_tuple: | |
| 194 | // CHECK: mov r7, sp | |
| 195 | // CHECK-NEXT: uxtb r0, r0 | |
| 196 | // CHECK-NEXT: orr.w r0, r0, r1, lsl #16 | |
| 197 | // CHECK-NEXT: bic r0, r0, #-16711936 | |
| 198 | #[no_mangle] | |
| 199 | extern "cmse-nonsecure-entry" fn cmse_ret_with_wide_u8_uninit_tuple( | |
| 200 | a: u16, | |
| 201 | b: u16, | |
| 202 | ) -> (MaybeUninit<WideU8>, MaybeUninit<WideU8>) { | |
| 203 | unsafe { (mem::transmute(a), mem::transmute(b)) } | |
| 204 | } |
tests/assembly-llvm/fentry.rs created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | //@ assembly-output: emit-asm | |
| 2 | //@ compile-flags: -Zinstrument-mcount=fentry | |
| 3 | //@ add-minicore | |
| 4 | ||
| 5 | //@ revisions: X86 S390X | |
| 6 | //@[X86] compile-flags: --target=x86_64-unknown-linux-gnu -Cllvm-args=-x86-asm-syntax=intel | |
| 7 | //@[X86] needs-llvm-components: x86 | |
| 8 | //@[S390X] compile-flags: --target=s390x-unknown-linux-gnu | |
| 9 | //@[S390X] needs-llvm-components: systemz | |
| 10 | ||
| 11 | #![crate_type = "lib"] | |
| 12 | #![feature(no_core)] | |
| 13 | #![no_core] | |
| 14 | ||
| 15 | extern crate minicore; | |
| 16 | ||
| 17 | // CHECK-LABEL: mcount_func: | |
| 18 | #[no_mangle] | |
| 19 | pub fn mcount_func(a: isize, b: isize) -> isize { | |
| 20 | // X86: call __fentry__ | |
| 21 | // S390X: brasl %r0, __fentry__@PLT | |
| 22 | a + b | |
| 23 | // X86: ret | |
| 24 | // S390X: br %r14 | |
| 25 | } |
tests/codegen-llvm/ilog_known_base.rs+4-4| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | // CHECK-LABEL: @checked_ilog2 |
| 8 | 8 | #[no_mangle] |
| 9 | 9 | pub fn checked_ilog2(val: u32) -> Option<u32> { |
| 10 | // CHECK: %[[ICMP:.+]] = icmp ne i32 %val, 0 | |
| 10 | // CHECK: icmp {{ne|eq}} i32 %val, 0 | |
| 11 | 11 | // CHECK: %[[CTZ:.+]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 %val, i1 true) |
| 12 | 12 | // CHECK: %[[LOG2:.+]] = xor i32 %[[CTZ]], 31 |
| 13 | 13 | val.checked_ilog(2) |
| ... | ... | @@ -17,7 +17,7 @@ pub fn checked_ilog2(val: u32) -> Option<u32> { |
| 17 | 17 | // CHECK-LABEL: @checked_ilog4 |
| 18 | 18 | #[no_mangle] |
| 19 | 19 | pub fn checked_ilog4(val: u32) -> Option<u32> { |
| 20 | // CHECK: %[[ICMP:.+]] = icmp ne i32 %val, 0 | |
| 20 | // CHECK: icmp {{ne|eq}} i32 %val, 0 | |
| 21 | 21 | // CHECK: %[[CTZ:.+]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 %val, i1 true) |
| 22 | 22 | // CHECK: %[[DIV2:.+]] = lshr i32 %[[CTZ]], 1 |
| 23 | 23 | // CHECK: %[[LOG4:.+]] = xor i32 %[[DIV2]], 15 |
| ... | ... | @@ -28,9 +28,9 @@ pub fn checked_ilog4(val: u32) -> Option<u32> { |
| 28 | 28 | // CHECK-LABEL: @checked_ilog16 |
| 29 | 29 | #[no_mangle] |
| 30 | 30 | pub fn checked_ilog16(val: u32) -> Option<u32> { |
| 31 | // CHECK: %[[ICMP:.+]] = icmp ne i32 %val, 0 | |
| 31 | // CHECK: icmp {{ne|eq}} i32 %val, 0 | |
| 32 | 32 | // CHECK: %[[CTZ:.+]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 %val, i1 true) |
| 33 | 33 | // CHECK: %[[DIV4:.+]] = lshr i32 %[[CTZ]], 2 |
| 34 | // CHECK: %[[LOG16:.+]] = xor i32 %[[DIV2]], 7 | |
| 34 | // CHECK: %[[LOG16:.+]] = xor i32 %[[DIV4]], 7 | |
| 35 | 35 | val.checked_ilog(16) |
| 36 | 36 | } |
tests/codegen-llvm/instrument-fentry.rs created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | //@ add-minicore | |
| 2 | //@ compile-flags: -Z instrument-mcount=fentry -Copt-level=0 | |
| 3 | // | |
| 4 | //@ revisions: x86_64-linux | |
| 5 | //@[x86_64-linux] compile-flags: --target=x86_64-unknown-linux-gnu | |
| 6 | //@[x86_64-linux] needs-llvm-components: x86 | |
| 7 | // | |
| 8 | //@ revisions: x86-linux | |
| 9 | //@[x86-linux] compile-flags: --target=i686-unknown-linux-gnu | |
| 10 | //@[x86-linux] needs-llvm-components: x86 | |
| 11 | // | |
| 12 | //@ revisions: s390x-linux | |
| 13 | //@[s390x-linux] compile-flags: --target=s390x-unknown-linux-gnu | |
| 14 | //@[s390x-linux] needs-llvm-components: systemz | |
| 15 | ||
| 16 | #![feature(no_core)] | |
| 17 | #![no_std] | |
| 18 | #![no_core] | |
| 19 | #![crate_type = "lib"] | |
| 20 | ||
| 21 | extern crate minicore; | |
| 22 | use minicore::*; | |
| 23 | ||
| 24 | // CHECK: attributes #{{.*}} "fentry-call"="true" | |
| 25 | pub fn foo() {} |
tests/codegen-llvm/instrument_fn.rs+8-1| ... | ... | @@ -1,10 +1,13 @@ |
| 1 | 1 | // Verify the #[instrument_fn] applies the correct LLVM IR function attributes. |
| 2 | 2 | // |
| 3 | //@ revisions:XRAY MCOUNT | |
| 3 | //@ revisions:XRAY MCOUNT FENTRY | |
| 4 | 4 | //@ add-minicore |
| 5 | 5 | //@ compile-flags: -Copt-level=0 |
| 6 | 6 | //@ [XRAY] compile-flags: -Zinstrument-xray --target=x86_64-unknown-linux-gnu |
| 7 | 7 | //@ [XRAY] needs-llvm-components: x86 |
| 8 | //@ [FENTRY] compile-flags: -Zinstrument-mcount=fentry -Copt-level=0 | |
| 9 | //@ [FENTRY] compile-flags: --target=x86_64-unknown-linux-gnu | |
| 10 | //@ [FENTRY] needs-llvm-components: x86 | |
| 8 | 11 | //@ [MCOUNT] compile-flags: -Zinstrument-mcount |
| 9 | 12 | |
| 10 | 13 | #![feature(no_core)] |
| ... | ... | @@ -27,12 +30,16 @@ fn instrument_off() {} |
| 27 | 30 | #[no_mangle] |
| 28 | 31 | #[instrument_fn = "on"] |
| 29 | 32 | // MCOUNT: define {{.*}}void @instrument_on() {{.*}} [[DFLT_ATTR]] |
| 33 | // FENTRY: define void @instrument_on() {{.*}} [[DFLT_ATTR]] | |
| 30 | 34 | // XRAY: define void @instrument_on() {{.*}} [[ON_ATTR:#[0-9]+]] |
| 31 | 35 | fn instrument_on() {} |
| 32 | 36 | |
| 33 | 37 | // MCOUNT: attributes [[DFLT_ATTR]] {{.*}} "instrument-function-entry-inlined"= |
| 34 | 38 | // MCOUNT-NOT: attributes [[OFF_ATTR]] {{.*}} "instrument-function-entry-inlined"= |
| 35 | 39 | |
| 40 | // FENTRY: attributes [[DFLT_ATTR]] {{.*}} "fentry-call"="true" | |
| 41 | // FENTRY-NOT: attributes [[OFF_ATTR]] {{.*}} "fentry-call"="true" | |
| 42 | ||
| 36 | 43 | // XRAY-NOT: attributes [[DFLT_ATTR]] {{.*}} "function-instrument"="xray-always" |
| 37 | 44 | // XRAY-NOT: attributes [[DFLT_ATTR]] {{.*}} "function-instrument"="xray-never" |
| 38 | 45 | // XRAY-NOT: attributes [[DFLT_ATTR]] {{.*}} "xray-skip-exit" |
tests/codegen-llvm/issues/issue-107681-unwrap_unchecked.rs+5-5| ... | ... | @@ -1,4 +1,6 @@ |
| 1 | 1 | //@ compile-flags: -Copt-level=3 |
| 2 | //@ filecheck-flags: --implicit-check-not 'br {{.*}}' --implicit-check-not 'select' | |
| 3 | //@ min-llvm-version: 22 | |
| 2 | 4 | |
| 3 | 5 | // Test for #107681. |
| 4 | 6 | // Make sure we don't create `br` or `select` instructions. |
| ... | ... | @@ -11,10 +13,8 @@ use std::slice::Iter; |
| 11 | 13 | #[no_mangle] |
| 12 | 14 | pub unsafe fn foo(x: &mut Copied<Iter<'_, u32>>) -> u32 { |
| 13 | 15 | // CHECK-LABEL: @foo( |
| 14 | // CHECK-NOT: br {{.*}} | |
| 15 | // CHECK-NOT: select | |
| 16 | // CHECK: [[RET:%.*]] = load i32, ptr | |
| 17 | // CHECK-NEXT: assume | |
| 18 | // CHECK-NEXT: ret i32 [[RET]] | |
| 16 | // CHECK: [[INNER:%.*]] = load ptr, ptr %x | |
| 17 | // CHECK: [[RET:%.*]] = load i32, ptr [[INNER]] | |
| 18 | // CHECK: ret i32 [[RET]] | |
| 19 | 19 | x.next().unwrap_unchecked() |
| 20 | 20 | } |
tests/pretty/auxiliary/to-reuse-functions.rs deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | //@ edition:2021 | |
| 2 | ||
| 3 | #[must_use] | |
| 4 | #[cold] | |
| 5 | pub unsafe fn unsafe_fn_extern() -> usize { 1 } | |
| 6 | ||
| 7 | #[must_use = "extern_fn_extern: some reason"] | |
| 8 | #[deprecated] | |
| 9 | pub extern "C" fn extern_fn_extern() -> usize { 1 } | |
| 10 | ||
| 11 | pub const fn const_fn_extern() -> usize { 1 } | |
| 12 | ||
| 13 | #[must_use] | |
| 14 | pub async fn async_fn_extern() { } |
tests/pretty/delegation-impl-reuse.pp deleted-45| ... | ... | @@ -1,45 +0,0 @@ |
| 1 | #![feature(prelude_import)] | |
| 2 | #![no_std] | |
| 3 | //@ pretty-compare-only | |
| 4 | //@ pretty-mode:expanded | |
| 5 | //@ pp-exact:delegation-impl-reuse.pp | |
| 6 | ||
| 7 | #![allow(incomplete_features)] | |
| 8 | #![feature(fn_delegation)] | |
| 9 | extern crate std; | |
| 10 | #[prelude_import] | |
| 11 | use ::std::prelude::rust_2015::*; | |
| 12 | ||
| 13 | trait Trait<T> { | |
| 14 | fn foo(&self) {} | |
| 15 | fn bar(&self) {} | |
| 16 | fn baz(&self) {} | |
| 17 | } | |
| 18 | ||
| 19 | struct S; | |
| 20 | ||
| 21 | impl Trait<{ | |
| 22 | struct S; | |
| 23 | 0 | |
| 24 | }> for S { | |
| 25 | reuse Trait<{ | |
| 26 | struct S; | |
| 27 | 0 | |
| 28 | }>::foo { | |
| 29 | self.0 | |
| 30 | } | |
| 31 | reuse Trait<{ | |
| 32 | struct S; | |
| 33 | 0 | |
| 34 | }>::bar { | |
| 35 | self.0 | |
| 36 | } | |
| 37 | reuse Trait<{ | |
| 38 | struct S; | |
| 39 | 0 | |
| 40 | }>::baz { | |
| 41 | self.0 | |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | fn main() {} |
tests/pretty/delegation-impl-reuse.rs deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:expanded | |
| 3 | //@ pp-exact:delegation-impl-reuse.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![feature(fn_delegation)] | |
| 7 | ||
| 8 | trait Trait<T> { | |
| 9 | fn foo(&self) {} | |
| 10 | fn bar(&self) {} | |
| 11 | fn baz(&self) {} | |
| 12 | } | |
| 13 | ||
| 14 | struct S; | |
| 15 | ||
| 16 | reuse impl Trait<{ struct S; 0 }> for S { self.0 } | |
| 17 | ||
| 18 | fn main() {} |
tests/pretty/delegation-inherit-attributes.pp deleted-124| ... | ... | @@ -1,124 +0,0 @@ |
| 1 | //@ edition:2021 | |
| 2 | //@ aux-crate:to_reuse_functions=to-reuse-functions.rs | |
| 3 | //@ pretty-mode:hir | |
| 4 | //@ pretty-compare-only | |
| 5 | //@ pp-exact:delegation-inherit-attributes.pp | |
| 6 | ||
| 7 | #![allow(incomplete_features)] | |
| 8 | #![attr = Feature([fn_delegation#0])] | |
| 9 | extern crate std; | |
| 10 | #[attr = PreludeImport] | |
| 11 | use std::prelude::rust_2021::*; | |
| 12 | ||
| 13 | extern crate to_reuse_functions; | |
| 14 | ||
| 15 | mod to_reuse { | |
| 16 | #[attr = MustUse {reason: "foo: some reason"}] | |
| 17 | #[attr = Cold] | |
| 18 | fn foo(x: usize) -> usize { x } | |
| 19 | ||
| 20 | #[attr = MustUse] | |
| 21 | #[attr = Cold] | |
| 22 | fn foo_no_reason(x: usize) -> usize { x } | |
| 23 | ||
| 24 | #[attr = Cold] | |
| 25 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 26 | fn bar(x: usize) -> usize { x } | |
| 27 | } | |
| 28 | ||
| 29 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 30 | #[attr = MustUse {reason: "foo: some reason"}] | |
| 31 | #[attr = Inline(Hint)] | |
| 32 | fn foo1(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 33 | ||
| 34 | #[attr = MustUse] | |
| 35 | #[attr = Inline(Hint)] | |
| 36 | fn foo_no_reason(arg0: _) -> _ { to_reuse::foo_no_reason(self + 1) } | |
| 37 | ||
| 38 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 39 | #[attr = MustUse {reason: "some reason"}] | |
| 40 | #[attr = Inline(Hint)] | |
| 41 | fn foo2(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 42 | ||
| 43 | #[attr = Inline(Hint)] | |
| 44 | fn bar(arg0: _) -> _ { to_reuse::bar(arg0) } | |
| 45 | ||
| 46 | #[attr = MustUse] | |
| 47 | #[attr = Inline(Hint)] | |
| 48 | unsafe fn unsafe_fn_extern() -> _ { to_reuse_functions::unsafe_fn_extern() } | |
| 49 | #[attr = MustUse {reason: "extern_fn_extern: some reason"}] | |
| 50 | #[attr = Inline(Hint)] | |
| 51 | extern "C" fn extern_fn_extern() | |
| 52 | -> _ { to_reuse_functions::extern_fn_extern() } | |
| 53 | #[attr = Inline(Hint)] | |
| 54 | const fn const_fn_extern() -> _ { to_reuse_functions::const_fn_extern() } | |
| 55 | #[attr = MustUse {reason: "some reason"}] | |
| 56 | #[attr = Inline(Hint)] | |
| 57 | async fn async_fn_extern() -> _ { to_reuse_functions::async_fn_extern() } | |
| 58 | ||
| 59 | mod recursive { | |
| 60 | // Check that `baz` inherit attribute from `foo` | |
| 61 | mod first { | |
| 62 | fn bar() { } | |
| 63 | #[attr = MustUse {reason: "some reason"}] | |
| 64 | #[attr = Inline(Hint)] | |
| 65 | fn foo() -> _ { bar() } | |
| 66 | #[attr = MustUse {reason: "some reason"}] | |
| 67 | #[attr = Inline(Hint)] | |
| 68 | fn baz() -> _ { foo() } | |
| 69 | } | |
| 70 | ||
| 71 | // Check that `baz` inherit attribute from `bar` | |
| 72 | mod second { | |
| 73 | #[attr = MustUse {reason: "some reason"}] | |
| 74 | fn bar() { } | |
| 75 | ||
| 76 | #[attr = MustUse {reason: "some reason"}] | |
| 77 | #[attr = Inline(Hint)] | |
| 78 | fn foo() -> _ { bar() } | |
| 79 | #[attr = MustUse {reason: "some reason"}] | |
| 80 | #[attr = Inline(Hint)] | |
| 81 | fn baz() -> _ { foo() } | |
| 82 | } | |
| 83 | ||
| 84 | // Check that `foo5` don't inherit attribute from `bar` | |
| 85 | // and inherit attribute from foo4, check that foo1, foo2 and foo3 | |
| 86 | // inherit attribute from bar | |
| 87 | mod third { | |
| 88 | #[attr = MustUse {reason: "some reason"}] | |
| 89 | fn bar() { } | |
| 90 | #[attr = MustUse {reason: "some reason"}] | |
| 91 | #[attr = Inline(Hint)] | |
| 92 | fn foo1() -> _ { bar() } | |
| 93 | #[attr = MustUse {reason: "some reason"}] | |
| 94 | #[attr = Inline(Hint)] | |
| 95 | fn foo2() -> _ { foo1() } | |
| 96 | #[attr = MustUse {reason: "some reason"}] | |
| 97 | #[attr = Inline(Hint)] | |
| 98 | fn foo3() -> _ { foo2() } | |
| 99 | #[attr = MustUse {reason: "foo4"}] | |
| 100 | #[attr = Inline(Hint)] | |
| 101 | fn foo4() -> _ { foo3() } | |
| 102 | #[attr = MustUse {reason: "foo4"}] | |
| 103 | #[attr = Inline(Hint)] | |
| 104 | fn foo5() -> _ { foo4() } | |
| 105 | } | |
| 106 | ||
| 107 | mod fourth { | |
| 108 | trait T { | |
| 109 | fn foo(&self, x: usize) -> usize { x + 1 } | |
| 110 | } | |
| 111 | ||
| 112 | struct X; | |
| 113 | impl T for X { } | |
| 114 | ||
| 115 | #[attr = MustUse {reason: "some reason"}] | |
| 116 | #[attr = Inline(Hint)] | |
| 117 | fn foo(self: _, arg1: _) -> _ { <X as T>::foo(self + 1, arg1) } | |
| 118 | #[attr = MustUse {reason: "some reason"}] | |
| 119 | #[attr = Inline(Hint)] | |
| 120 | fn bar(arg0: _, arg1: _) -> _ { foo(self + 1, arg1) } | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | fn main() { } |
tests/pretty/delegation-inherit-attributes.rs deleted-101| ... | ... | @@ -1,101 +0,0 @@ |
| 1 | //@ edition:2021 | |
| 2 | //@ aux-crate:to_reuse_functions=to-reuse-functions.rs | |
| 3 | //@ pretty-mode:hir | |
| 4 | //@ pretty-compare-only | |
| 5 | //@ pp-exact:delegation-inherit-attributes.pp | |
| 6 | ||
| 7 | #![allow(incomplete_features)] | |
| 8 | #![feature(fn_delegation)] | |
| 9 | ||
| 10 | extern crate to_reuse_functions; | |
| 11 | ||
| 12 | mod to_reuse { | |
| 13 | #[must_use = "foo: some reason"] | |
| 14 | #[cold] | |
| 15 | pub fn foo(x: usize) -> usize { | |
| 16 | x | |
| 17 | } | |
| 18 | ||
| 19 | #[must_use] | |
| 20 | #[cold] | |
| 21 | pub fn foo_no_reason(x: usize) -> usize { | |
| 22 | x | |
| 23 | } | |
| 24 | ||
| 25 | #[cold] | |
| 26 | #[deprecated] | |
| 27 | pub fn bar(x: usize) -> usize { | |
| 28 | x | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | #[deprecated] | |
| 33 | reuse to_reuse::foo as foo1 { | |
| 34 | self + 1 | |
| 35 | } | |
| 36 | ||
| 37 | reuse to_reuse::foo_no_reason { | |
| 38 | self + 1 | |
| 39 | } | |
| 40 | ||
| 41 | #[deprecated] | |
| 42 | #[must_use = "some reason"] | |
| 43 | reuse to_reuse::foo as foo2 { | |
| 44 | self + 1 | |
| 45 | } | |
| 46 | ||
| 47 | reuse to_reuse::bar; | |
| 48 | ||
| 49 | reuse to_reuse_functions::unsafe_fn_extern; | |
| 50 | reuse to_reuse_functions::extern_fn_extern; | |
| 51 | reuse to_reuse_functions::const_fn_extern; | |
| 52 | #[must_use = "some reason"] | |
| 53 | reuse to_reuse_functions::async_fn_extern; | |
| 54 | ||
| 55 | mod recursive { | |
| 56 | // Check that `baz` inherit attribute from `foo` | |
| 57 | mod first { | |
| 58 | fn bar() {} | |
| 59 | #[must_use = "some reason"] | |
| 60 | reuse bar as foo; | |
| 61 | reuse foo as baz; | |
| 62 | } | |
| 63 | ||
| 64 | // Check that `baz` inherit attribute from `bar` | |
| 65 | mod second { | |
| 66 | #[must_use = "some reason"] | |
| 67 | fn bar() {} | |
| 68 | ||
| 69 | reuse bar as foo; | |
| 70 | reuse foo as baz; | |
| 71 | } | |
| 72 | ||
| 73 | // Check that `foo5` don't inherit attribute from `bar` | |
| 74 | // and inherit attribute from foo4, check that foo1, foo2 and foo3 | |
| 75 | // inherit attribute from bar | |
| 76 | mod third { | |
| 77 | #[must_use = "some reason"] | |
| 78 | fn bar() {} | |
| 79 | reuse bar as foo1; | |
| 80 | reuse foo1 as foo2; | |
| 81 | reuse foo2 as foo3; | |
| 82 | #[must_use = "foo4"] | |
| 83 | reuse foo3 as foo4; | |
| 84 | reuse foo4 as foo5; | |
| 85 | } | |
| 86 | ||
| 87 | mod fourth { | |
| 88 | trait T { | |
| 89 | fn foo(&self, x: usize) -> usize { x + 1 } | |
| 90 | } | |
| 91 | ||
| 92 | struct X; | |
| 93 | impl T for X {} | |
| 94 | ||
| 95 | #[must_use = "some reason"] | |
| 96 | reuse <X as T>::foo { self + 1 } | |
| 97 | reuse foo as bar { self + 1 } | |
| 98 | } | |
| 99 | } | |
| 100 | ||
| 101 | fn main() {} |
tests/pretty/delegation-inline-attribute.pp deleted-92| ... | ... | @@ -1,92 +0,0 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:delegation-inline-attribute.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![attr = Feature([fn_delegation#0])] | |
| 7 | extern crate std; | |
| 8 | #[attr = PreludeImport] | |
| 9 | use ::std::prelude::rust_2015::*; | |
| 10 | ||
| 11 | mod to_reuse { | |
| 12 | fn foo(x: usize) -> usize { x } | |
| 13 | } | |
| 14 | ||
| 15 | // Check that #[inline(hint)] is added to foo reuse | |
| 16 | #[attr = Inline(Hint)] | |
| 17 | fn bar(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 18 | ||
| 19 | trait Trait { | |
| 20 | fn foo(&self) { } | |
| 21 | fn foo1(&self) { } | |
| 22 | fn foo2(&self) { } | |
| 23 | fn foo3(&self) { } | |
| 24 | fn foo4(&self) { } | |
| 25 | } | |
| 26 | ||
| 27 | impl Trait for u8 { } | |
| 28 | ||
| 29 | struct S(u8); | |
| 30 | ||
| 31 | mod to_import { | |
| 32 | fn check(arg: &'_ u8) -> &'_ u8 { arg } | |
| 33 | } | |
| 34 | ||
| 35 | impl Trait for S { | |
| 36 | // Check that #[inline(hint)] is added to foo reuse | |
| 37 | #[attr = Inline(Hint)] | |
| 38 | fn foo(self: _) | |
| 39 | -> | |
| 40 | _ { | |
| 41 | // Check that #[inline(hint)] is added to foo0 reuse inside another reuse | |
| 42 | #[attr = Inline(Hint)] | |
| 43 | fn foo0(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 44 | ||
| 45 | // Check that #[inline(hint)] is added when other attributes present in inner reuse | |
| 46 | #[attr = Cold] | |
| 47 | #[attr = MustUse] | |
| 48 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 49 | #[attr = Inline(Hint)] | |
| 50 | fn foo1(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 51 | ||
| 52 | // Check that #[inline(never)] is preserved in inner reuse | |
| 53 | #[attr = Inline(Never)] | |
| 54 | fn foo2(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 55 | ||
| 56 | // Check that #[inline(always)] is preserved in inner reuse | |
| 57 | #[attr = Inline(Always)] | |
| 58 | fn foo3(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 59 | ||
| 60 | // Check that #[inline(never)] is preserved when there are other attributes in inner reuse | |
| 61 | #[attr = Cold] | |
| 62 | #[attr = MustUse] | |
| 63 | #[attr = Inline(Never)] | |
| 64 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 65 | fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 66 | Trait::foo(self) | |
| 67 | } | |
| 68 | ||
| 69 | // Check that #[inline(hint)] is added when there are other attributes present in trait reuse | |
| 70 | #[attr = Cold] | |
| 71 | #[attr = MustUse] | |
| 72 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 73 | #[attr = Inline(Hint)] | |
| 74 | fn foo1(self: _) -> _ { Trait::foo1(self.0) } | |
| 75 | ||
| 76 | // Check that #[inline(never)] is preserved in trait reuse | |
| 77 | #[attr = Inline(Never)] | |
| 78 | fn foo2(self: _) -> _ { Trait::foo2(self.0) } | |
| 79 | ||
| 80 | // Check that #[inline(always)] is preserved in trait reuse | |
| 81 | #[attr = Inline(Always)] | |
| 82 | fn foo3(self: _) -> _ { Trait::foo3(self.0) } | |
| 83 | ||
| 84 | // Check that #[inline(never)] is preserved when there are other attributes in trait reuse | |
| 85 | #[attr = Cold] | |
| 86 | #[attr = MustUse] | |
| 87 | #[attr = Inline(Never)] | |
| 88 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 89 | fn foo4(self: _) -> _ { Trait::foo4(self.0) } | |
| 90 | } | |
| 91 | ||
| 92 | fn main() { } |
tests/pretty/delegation-inline-attribute.rs deleted-104| ... | ... | @@ -1,104 +0,0 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:delegation-inline-attribute.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![feature(fn_delegation)] | |
| 7 | ||
| 8 | mod to_reuse { | |
| 9 | pub fn foo(x: usize) -> usize { | |
| 10 | x | |
| 11 | } | |
| 12 | } | |
| 13 | ||
| 14 | // Check that #[inline(hint)] is added to foo reuse | |
| 15 | reuse to_reuse::foo as bar { | |
| 16 | self + 1 | |
| 17 | } | |
| 18 | ||
| 19 | trait Trait { | |
| 20 | fn foo(&self) {} | |
| 21 | fn foo1(&self) {} | |
| 22 | fn foo2(&self) {} | |
| 23 | fn foo3(&self) {} | |
| 24 | fn foo4(&self) {} | |
| 25 | } | |
| 26 | ||
| 27 | impl Trait for u8 {} | |
| 28 | ||
| 29 | struct S(u8); | |
| 30 | ||
| 31 | mod to_import { | |
| 32 | pub fn check(arg: &u8) -> &u8 { arg } | |
| 33 | } | |
| 34 | ||
| 35 | impl Trait for S { | |
| 36 | // Check that #[inline(hint)] is added to foo reuse | |
| 37 | reuse Trait::foo { | |
| 38 | // Check that #[inline(hint)] is added to foo0 reuse inside another reuse | |
| 39 | reuse to_reuse::foo as foo0 { | |
| 40 | self + 1 | |
| 41 | } | |
| 42 | ||
| 43 | // Check that #[inline(hint)] is added when other attributes present in inner reuse | |
| 44 | #[cold] | |
| 45 | #[must_use] | |
| 46 | #[deprecated] | |
| 47 | reuse to_reuse::foo as foo1 { | |
| 48 | self / 2 | |
| 49 | } | |
| 50 | ||
| 51 | // Check that #[inline(never)] is preserved in inner reuse | |
| 52 | #[inline(never)] | |
| 53 | reuse to_reuse::foo as foo2 { | |
| 54 | self / 2 | |
| 55 | } | |
| 56 | ||
| 57 | // Check that #[inline(always)] is preserved in inner reuse | |
| 58 | #[inline(always)] | |
| 59 | reuse to_reuse::foo as foo3 { | |
| 60 | self / 2 | |
| 61 | } | |
| 62 | ||
| 63 | // Check that #[inline(never)] is preserved when there are other attributes in inner reuse | |
| 64 | #[cold] | |
| 65 | #[must_use] | |
| 66 | #[inline(never)] | |
| 67 | #[deprecated] | |
| 68 | reuse to_reuse::foo as foo4 { | |
| 69 | self / 2 | |
| 70 | } | |
| 71 | } | |
| 72 | ||
| 73 | // Check that #[inline(hint)] is added when there are other attributes present in trait reuse | |
| 74 | #[cold] | |
| 75 | #[must_use] | |
| 76 | #[deprecated] | |
| 77 | reuse Trait::foo1 { | |
| 78 | self.0 | |
| 79 | } | |
| 80 | ||
| 81 | // Check that #[inline(never)] is preserved in trait reuse | |
| 82 | #[inline(never)] | |
| 83 | reuse Trait::foo2 { | |
| 84 | self.0 | |
| 85 | } | |
| 86 | ||
| 87 | // Check that #[inline(always)] is preserved in trait reuse | |
| 88 | #[inline(always)] | |
| 89 | reuse Trait::foo3 { | |
| 90 | self.0 | |
| 91 | } | |
| 92 | ||
| 93 | // Check that #[inline(never)] is preserved when there are other attributes in trait reuse | |
| 94 | #[cold] | |
| 95 | #[must_use] | |
| 96 | #[inline(never)] | |
| 97 | #[deprecated] | |
| 98 | reuse Trait::foo4 { | |
| 99 | self.0 | |
| 100 | } | |
| 101 | } | |
| 102 | ||
| 103 | fn main() { | |
| 104 | } |
tests/pretty/delegation-self-rename.pp deleted-58| ... | ... | @@ -1,58 +0,0 @@ |
| 1 | #![attr = Feature([fn_delegation#0])] | |
| 2 | extern crate std; | |
| 3 | #[attr = PreludeImport] | |
| 4 | use ::std::prelude::rust_2015::*; | |
| 5 | //@ pretty-compare-only | |
| 6 | //@ pretty-mode:hir | |
| 7 | //@ pp-exact:delegation-self-rename.pp | |
| 8 | ||
| 9 | ||
| 10 | trait Trait<'a, A, const B: bool> { | |
| 11 | fn foo<'b, const B2: bool, T, U, | |
| 12 | impl FnOnce() -> usize>(&self, f: impl FnOnce() -> usize) -> usize | |
| 13 | where impl FnOnce() -> usize: FnOnce() -> usize { f() + 1 } | |
| 14 | } | |
| 15 | ||
| 16 | struct X; | |
| 17 | impl <'a, A, const B: bool> Trait<'a, A, B> for X { } | |
| 18 | ||
| 19 | #[attr = Inline(Hint)] | |
| 20 | fn foo<'a, Self, A, const B: _, const B2: _, T, U, | |
| 21 | impl FnOnce() -> usize>(self: _, arg1: _) -> _ where | |
| 22 | 'a:'a { <Self as Trait::<'a, A, B>>::foo::<B2, T, U>(self, arg1) } | |
| 23 | #[attr = Inline(Hint)] | |
| 24 | fn bar<Self, impl FnOnce() -> usize>(self: _, arg1: _) | |
| 25 | -> | |
| 26 | _ { | |
| 27 | <Self as Trait::<'static, (), true>>::foo::<true, (), ()>(self, arg1) | |
| 28 | } | |
| 29 | ||
| 30 | #[attr = Inline(Hint)] | |
| 31 | fn foo2<'a, This, A, const B: _, const B2: _, T, U, | |
| 32 | impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where | |
| 33 | 'a:'a { foo::<'a, This, A, B, B2, T, U>(arg0, arg1) } | |
| 34 | #[attr = Inline(Hint)] | |
| 35 | fn bar2<This, impl FnOnce() -> usize>(arg0: _, arg1: _) | |
| 36 | -> _ { bar::<This>(arg0, arg1) } | |
| 37 | ||
| 38 | trait Trait2 { | |
| 39 | #[attr = Inline(Hint)] | |
| 40 | fn foo3<'a, This, A, const B: _, const B2: _, T, U, | |
| 41 | impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where | |
| 42 | 'a:'a { foo2::<'a, This, A, B, B2, T, U>(arg0, arg1) } | |
| 43 | #[attr = Inline(Hint)] | |
| 44 | fn bar3<This, impl FnOnce() -> usize>(arg0: _, arg1: _) | |
| 45 | -> _ { bar2::<This>(arg0, arg1) } | |
| 46 | } | |
| 47 | ||
| 48 | impl Trait2 for () { } | |
| 49 | ||
| 50 | #[attr = Inline(Hint)] | |
| 51 | fn foo4<'a, This, A, const B: _, const B2: _, T, U, | |
| 52 | impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where | |
| 53 | 'a:'a { <() as Trait2>::foo3::<'a, This, A, B, B2, T, U>(arg0, arg1) } | |
| 54 | #[attr = Inline(Hint)] | |
| 55 | fn bar4<This, impl FnOnce() -> usize>(arg0: _, arg1: _) | |
| 56 | -> _ { <() as Trait2>::bar3::<This>(arg0, arg1) } | |
| 57 | ||
| 58 | fn main() { } |
tests/pretty/delegation-self-rename.rs deleted-32| ... | ... | @@ -1,32 +0,0 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:delegation-self-rename.pp | |
| 4 | ||
| 5 | #![feature(fn_delegation)] | |
| 6 | ||
| 7 | trait Trait<'a, A, const B: bool> { | |
| 8 | fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { | |
| 9 | f() + 1 | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | struct X; | |
| 14 | impl<'a, A, const B: bool> Trait<'a, A, B> for X {} | |
| 15 | ||
| 16 | reuse Trait::foo; | |
| 17 | reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar; | |
| 18 | ||
| 19 | reuse foo as foo2; | |
| 20 | reuse bar as bar2; | |
| 21 | ||
| 22 | trait Trait2 { | |
| 23 | reuse foo2 as foo3; | |
| 24 | reuse bar2 as bar3; | |
| 25 | } | |
| 26 | ||
| 27 | impl Trait2 for () {} | |
| 28 | ||
| 29 | reuse <() as Trait2>::foo3 as foo4; | |
| 30 | reuse <() as Trait2>::bar3 as bar4; | |
| 31 | ||
| 32 | fn main() {} |
tests/pretty/delegation.rs deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | #![feature(fn_delegation)] | |
| 2 | //~^ WARN the feature `fn_delegation` is incomplete | |
| 3 | ||
| 4 | //@ pp-exact | |
| 5 | ||
| 6 | trait Trait { | |
| 7 | fn bar(&self, x: i32) -> i32 { x } | |
| 8 | } | |
| 9 | ||
| 10 | struct F; | |
| 11 | impl Trait for F {} | |
| 12 | ||
| 13 | struct S(F); | |
| 14 | impl Trait for S { | |
| 15 | reuse Trait::bar { &self.0 } | |
| 16 | } | |
| 17 | ||
| 18 | mod to_reuse { | |
| 19 | pub fn foo() {} | |
| 20 | } | |
| 21 | ||
| 22 | #[inline] | |
| 23 | pub reuse to_reuse::foo; | |
| 24 | ||
| 25 | fn main() {} |
tests/pretty/delegation/auxiliary/to-reuse-functions.rs created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | //@ edition:2021 | |
| 2 | ||
| 3 | #[must_use] | |
| 4 | #[cold] | |
| 5 | pub unsafe fn unsafe_fn_extern() -> usize { 1 } | |
| 6 | ||
| 7 | #[must_use = "extern_fn_extern: some reason"] | |
| 8 | #[deprecated] | |
| 9 | pub extern "C" fn extern_fn_extern() -> usize { 1 } | |
| 10 | ||
| 11 | pub const fn const_fn_extern() -> usize { 1 } | |
| 12 | ||
| 13 | #[must_use] | |
| 14 | pub async fn async_fn_extern() { } |
tests/pretty/delegation/delegation.rs created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | #![feature(fn_delegation)] | |
| 2 | //~^ WARN the feature `fn_delegation` is incomplete | |
| 3 | ||
| 4 | //@ pp-exact | |
| 5 | ||
| 6 | trait Trait { | |
| 7 | fn bar(&self, x: i32) -> i32 { x } | |
| 8 | } | |
| 9 | ||
| 10 | struct F; | |
| 11 | impl Trait for F {} | |
| 12 | ||
| 13 | struct S(F); | |
| 14 | impl Trait for S { | |
| 15 | reuse Trait::bar { &self.0 } | |
| 16 | } | |
| 17 | ||
| 18 | mod to_reuse { | |
| 19 | pub fn foo() {} | |
| 20 | } | |
| 21 | ||
| 22 | #[inline] | |
| 23 | pub reuse to_reuse::foo; | |
| 24 | ||
| 25 | fn main() {} |
tests/pretty/delegation/generics.pp created+131| ... | ... | @@ -0,0 +1,131 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:generics.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![attr = Feature([fn_delegation#0])] | |
| 7 | extern crate std; | |
| 8 | #[attr = PreludeImport] | |
| 9 | use ::std::prelude::rust_2015::*; | |
| 10 | ||
| 11 | mod free_to_trait { | |
| 12 | trait Trait<'a, XX, Y, T = (), const N: usize = 2> { | |
| 13 | fn method<A, B>(&self, t: (T, A, B), slice: &'_ [usize; N]) { } | |
| 14 | fn r#static<A, B>(t: (T, A, B), slice: &'_ [usize; N]) { } | |
| 15 | } | |
| 16 | ||
| 17 | struct X; | |
| 18 | impl <XX, Y, T, const N: usize> Trait<'_, XX, Y, T, N> for X { } | |
| 19 | ||
| 20 | // When infer is specified for default parameter the generic param is generated. | |
| 21 | #[attr = Inline(Hint)] | |
| 22 | fn foo<'a, Self, XX, Y, T, const N: _, A, B>(self: _, arg1: _, arg2: _) | |
| 23 | -> _ where | |
| 24 | 'a:'a { | |
| 25 | <Self as Trait::<'a, XX, Y, T, N>>::method::<A, B>(self, arg1, arg2) | |
| 26 | } | |
| 27 | #[attr = Inline(Hint)] | |
| 28 | fn static_foo<'a, Self, XX, Y, T, const N: _, A, B>(arg0: _, arg1: _) -> _ | |
| 29 | where | |
| 30 | 'a:'a { | |
| 31 | <Self as Trait::<'a, XX, Y, T, N>>::r#static::<A, B>(arg0, arg1) | |
| 32 | } | |
| 33 | ||
| 34 | // When default params are omitted they are not generated but used in signature inheritance. | |
| 35 | #[attr = Inline(Hint)] | |
| 36 | fn bar<'a, Self, XX, Y, A, B>(self: _, arg1: _, arg2: _) -> _ where | |
| 37 | 'a:'a { | |
| 38 | <Self as Trait::<'a, XX, Y>>::method::<A, B>(self, arg1, arg2) | |
| 39 | } | |
| 40 | #[attr = Inline(Hint)] | |
| 41 | fn static_bar<'a, Self, XX, Y, A, B>(arg0: _, arg1: _) -> _ where | |
| 42 | 'a:'a { <Self as Trait::<'a, XX, Y>>::r#static::<A, B>(arg0, arg1) } | |
| 43 | ||
| 44 | // Check with user specified args in child: | |
| 45 | // When infer is specified for default parameter the generic param is generated. | |
| 46 | #[attr = Inline(Hint)] | |
| 47 | fn foo1<'a, Self, XX, Y, T, const N: _, B>(self: _, arg1: _, arg2: _) -> _ | |
| 48 | where | |
| 49 | 'a:'a { | |
| 50 | <Self as Trait::<'a, XX, Y, T, N>>::method::<(), B>(self, arg1, arg2) | |
| 51 | } | |
| 52 | #[attr = Inline(Hint)] | |
| 53 | fn static_foo1<'a, Self, XX, Y, T, const N: _, B>(arg0: _, arg1: _) -> _ | |
| 54 | where | |
| 55 | 'a:'a { | |
| 56 | <Self as Trait::<'a, XX, Y, T, N>>::r#static::<(), B>(arg0, arg1) | |
| 57 | } | |
| 58 | ||
| 59 | // When default params are omitted they are not generated but used in signature inheritance. | |
| 60 | #[attr = Inline(Hint)] | |
| 61 | fn bar1<'a, Self, XX, Y, A>(self: _, arg1: _, arg2: _) -> _ where | |
| 62 | 'a:'a { | |
| 63 | <Self as Trait::<'a, XX, Y>>::method::<A, ()>(self, arg1, arg2) | |
| 64 | } | |
| 65 | #[attr = Inline(Hint)] | |
| 66 | fn static_bar1<'a, Self, XX, Y, A>(arg0: _, arg1: _) -> _ where | |
| 67 | 'a:'a { <Self as Trait::<'a, XX, Y>>::r#static::<A, ()>(arg0, arg1) } | |
| 68 | ||
| 69 | // Check with explicit self type. | |
| 70 | #[attr = Inline(Hint)] | |
| 71 | fn foo2<'a, XX, Y, T, const N: _, A, B>(self: _, arg1: _, arg2: _) -> _ | |
| 72 | where | |
| 73 | 'a:'a { | |
| 74 | <X as Trait::<'a, XX, Y, T, N>>::method::<A, B>(self, arg1, arg2) | |
| 75 | } | |
| 76 | #[attr = Inline(Hint)] | |
| 77 | fn static_foo2<'a, XX, Y, T, const N: _, A, B>(arg0: _, arg1: _) -> _ | |
| 78 | where | |
| 79 | 'a:'a { | |
| 80 | <X as Trait::<'a, XX, Y, T, N>>::r#static::<A, B>(arg0, arg1) | |
| 81 | } | |
| 82 | ||
| 83 | #[attr = Inline(Hint)] | |
| 84 | fn bar2<'a, XX, Y, A, B>(self: _, arg1: _, arg2: _) -> _ where | |
| 85 | 'a:'a { <X as Trait::<'a, XX, Y>>::method::<A, B>(self, arg1, arg2) } | |
| 86 | #[attr = Inline(Hint)] | |
| 87 | fn static_bar2<'a, XX, Y, A, B>(arg0: _, arg1: _) -> _ where | |
| 88 | 'a:'a { <X as Trait::<'a, XX, Y>>::r#static::<A, B>(arg0, arg1) } | |
| 89 | ||
| 90 | #[attr = Inline(Hint)] | |
| 91 | fn foo3<'a, XX, Y, T, const N: _, B>(self: _, arg1: _, arg2: _) -> _ where | |
| 92 | 'a:'a { | |
| 93 | <X as Trait::<'a, XX, Y, T, N>>::method::<(), B>(self, arg1, arg2) | |
| 94 | } | |
| 95 | #[attr = Inline(Hint)] | |
| 96 | fn static_foo3<'a, XX, Y, T, const N: _, B>(arg0: _, arg1: _) -> _ where | |
| 97 | 'a:'a { | |
| 98 | <X as Trait::<'a, XX, Y, T, N>>::r#static::<(), B>(arg0, arg1) | |
| 99 | } | |
| 100 | ||
| 101 | #[attr = Inline(Hint)] | |
| 102 | fn bar3<'a, XX, Y, A>(self: _, arg1: _, arg2: _) -> _ where | |
| 103 | 'a:'a { <X as Trait::<'a, XX, Y>>::method::<A, ()>(self, arg1, arg2) } | |
| 104 | #[attr = Inline(Hint)] | |
| 105 | fn static_bar3<'a, XX, Y, A>(arg0: _, arg1: _) -> _ where | |
| 106 | 'a:'a { <X as Trait::<'a, XX, Y>>::r#static::<A, ()>(arg0, arg1) } | |
| 107 | } | |
| 108 | ||
| 109 | mod trait_impl_to_trait { | |
| 110 | trait Trait<'a, X, Y, T = (), const N: usize = 2> { | |
| 111 | fn foo(&self, t: (T, T, T), slice: &'_ [usize; N]) { } | |
| 112 | fn bar(&self, t: (T, T, T), slice: &'_ [usize; N]) { } | |
| 113 | } | |
| 114 | ||
| 115 | struct S; | |
| 116 | impl <X, Y> Trait<'_, X, Y> for S { } | |
| 117 | ||
| 118 | struct W(S); | |
| 119 | impl <X, Y> Trait<'_, X, Y> for W { | |
| 120 | // Generics of both methods match generics of their signature | |
| 121 | // functions in `Trait` declaration, no matter specified infers. | |
| 122 | #[attr = Inline(Hint)] | |
| 123 | fn foo(self: _, arg1: _, arg2: _) | |
| 124 | -> _ { Trait::<'static, X, Y>::foo(self.0, arg1, arg2) } | |
| 125 | #[attr = Inline(Hint)] | |
| 126 | fn bar(self: _, arg1: _, arg2: _) | |
| 127 | -> _ { Trait::<'static, X, Y, _, _>::foo(self.0, arg1, arg2) } | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| 131 | fn main() { } |
tests/pretty/delegation/generics.rs created+66| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:generics.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![feature(fn_delegation)] | |
| 7 | ||
| 8 | mod free_to_trait { | |
| 9 | trait Trait<'a, XX, Y, T = (), const N: usize = 2> { | |
| 10 | fn method<A, B>(&self, t: (T, A, B), slice: &[usize; N]) {} | |
| 11 | fn r#static<A, B>(t: (T, A, B), slice: &[usize; N]) {} | |
| 12 | } | |
| 13 | ||
| 14 | struct X; | |
| 15 | impl<XX, Y, T, const N: usize> Trait<'_, XX, Y, T, N> for X {} | |
| 16 | ||
| 17 | // When infer is specified for default parameter the generic param is generated. | |
| 18 | reuse Trait::<'_, _, _, _, _>::method as foo; | |
| 19 | reuse Trait::<'_, _, _, _, _>::r#static as static_foo; | |
| 20 | ||
| 21 | // When default params are omitted they are not generated but used in signature inheritance. | |
| 22 | reuse Trait::<'_, _, _>::method as bar; | |
| 23 | reuse Trait::<'_, _, _>::r#static as static_bar; | |
| 24 | ||
| 25 | // Check with user specified args in child: | |
| 26 | // When infer is specified for default parameter the generic param is generated. | |
| 27 | reuse Trait::<'_, _, _, _, _>::method::<(), _> as foo1; | |
| 28 | reuse Trait::<'_, _, _, _, _>::r#static::<(), _> as static_foo1; | |
| 29 | ||
| 30 | // When default params are omitted they are not generated but used in signature inheritance. | |
| 31 | reuse Trait::<'_, _, _>::method::<_, ()> as bar1; | |
| 32 | reuse Trait::<'_, _, _>::r#static::<_, ()> as static_bar1; | |
| 33 | ||
| 34 | // Check with explicit self type. | |
| 35 | reuse <X as Trait::<'_, _, _, _, _>>::method as foo2; | |
| 36 | reuse <X as Trait::<'_, _, _, _, _>>::r#static as static_foo2; | |
| 37 | ||
| 38 | reuse <X as Trait::<'_, _, _>>::method as bar2; | |
| 39 | reuse <X as Trait::<'_, _, _>>::r#static as static_bar2; | |
| 40 | ||
| 41 | reuse <X as Trait::<'_, _, _, _, _>>::method::<(), _> as foo3; | |
| 42 | reuse <X as Trait::<'_, _, _, _, _>>::r#static::<(), _> as static_foo3; | |
| 43 | ||
| 44 | reuse <X as Trait::<'_, _, _>>::method::<_, ()> as bar3; | |
| 45 | reuse <X as Trait::<'_, _, _>>::r#static::<_, ()> as static_bar3; | |
| 46 | } | |
| 47 | ||
| 48 | mod trait_impl_to_trait { | |
| 49 | trait Trait<'a, X, Y, T = (), const N: usize = 2> { | |
| 50 | fn foo(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 51 | fn bar(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 52 | } | |
| 53 | ||
| 54 | struct S; | |
| 55 | impl<X, Y> Trait<'_, X, Y> for S {} | |
| 56 | ||
| 57 | struct W(S); | |
| 58 | impl<X, Y> Trait<'_, X, Y> for W { | |
| 59 | // Generics of both methods match generics of their signature | |
| 60 | // functions in `Trait` declaration, no matter specified infers. | |
| 61 | reuse Trait::<'static, X, Y>::foo { self.0 } | |
| 62 | reuse Trait::<'static, X, Y, _, _>::foo as bar { self.0 } | |
| 63 | } | |
| 64 | } | |
| 65 | ||
| 66 | fn main() {} |
tests/pretty/delegation/impl-reuse.pp created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | #![feature(prelude_import)] | |
| 2 | #![no_std] | |
| 3 | //@ pretty-compare-only | |
| 4 | //@ pretty-mode:expanded | |
| 5 | //@ pp-exact:impl-reuse.pp | |
| 6 | ||
| 7 | #![allow(incomplete_features)] | |
| 8 | #![feature(fn_delegation)] | |
| 9 | extern crate std; | |
| 10 | #[prelude_import] | |
| 11 | use ::std::prelude::rust_2015::*; | |
| 12 | ||
| 13 | trait Trait<T> { | |
| 14 | fn foo(&self) {} | |
| 15 | fn bar(&self) {} | |
| 16 | fn baz(&self) {} | |
| 17 | } | |
| 18 | ||
| 19 | struct S; | |
| 20 | ||
| 21 | impl Trait<{ | |
| 22 | struct S; | |
| 23 | 0 | |
| 24 | }> for S { | |
| 25 | reuse Trait<{ | |
| 26 | struct S; | |
| 27 | 0 | |
| 28 | }>::foo { | |
| 29 | self.0 | |
| 30 | } | |
| 31 | reuse Trait<{ | |
| 32 | struct S; | |
| 33 | 0 | |
| 34 | }>::bar { | |
| 35 | self.0 | |
| 36 | } | |
| 37 | reuse Trait<{ | |
| 38 | struct S; | |
| 39 | 0 | |
| 40 | }>::baz { | |
| 41 | self.0 | |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | fn main() {} |
tests/pretty/delegation/impl-reuse.rs created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:expanded | |
| 3 | //@ pp-exact:impl-reuse.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![feature(fn_delegation)] | |
| 7 | ||
| 8 | trait Trait<T> { | |
| 9 | fn foo(&self) {} | |
| 10 | fn bar(&self) {} | |
| 11 | fn baz(&self) {} | |
| 12 | } | |
| 13 | ||
| 14 | struct S; | |
| 15 | ||
| 16 | reuse impl Trait<{ struct S; 0 }> for S { self.0 } | |
| 17 | ||
| 18 | fn main() {} |
tests/pretty/delegation/inherit-attributes.pp created+124| ... | ... | @@ -0,0 +1,124 @@ |
| 1 | //@ edition:2021 | |
| 2 | //@ aux-crate:to_reuse_functions=to-reuse-functions.rs | |
| 3 | //@ pretty-mode:hir | |
| 4 | //@ pretty-compare-only | |
| 5 | //@ pp-exact:inherit-attributes.pp | |
| 6 | ||
| 7 | #![allow(incomplete_features)] | |
| 8 | #![attr = Feature([fn_delegation#0])] | |
| 9 | extern crate std; | |
| 10 | #[attr = PreludeImport] | |
| 11 | use std::prelude::rust_2021::*; | |
| 12 | ||
| 13 | extern crate to_reuse_functions; | |
| 14 | ||
| 15 | mod to_reuse { | |
| 16 | #[attr = MustUse {reason: "foo: some reason"}] | |
| 17 | #[attr = Cold] | |
| 18 | fn foo(x: usize) -> usize { x } | |
| 19 | ||
| 20 | #[attr = MustUse] | |
| 21 | #[attr = Cold] | |
| 22 | fn foo_no_reason(x: usize) -> usize { x } | |
| 23 | ||
| 24 | #[attr = Cold] | |
| 25 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 26 | fn bar(x: usize) -> usize { x } | |
| 27 | } | |
| 28 | ||
| 29 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 30 | #[attr = MustUse {reason: "foo: some reason"}] | |
| 31 | #[attr = Inline(Hint)] | |
| 32 | fn foo1(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 33 | ||
| 34 | #[attr = MustUse] | |
| 35 | #[attr = Inline(Hint)] | |
| 36 | fn foo_no_reason(arg0: _) -> _ { to_reuse::foo_no_reason(self + 1) } | |
| 37 | ||
| 38 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 39 | #[attr = MustUse {reason: "some reason"}] | |
| 40 | #[attr = Inline(Hint)] | |
| 41 | fn foo2(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 42 | ||
| 43 | #[attr = Inline(Hint)] | |
| 44 | fn bar(arg0: _) -> _ { to_reuse::bar(arg0) } | |
| 45 | ||
| 46 | #[attr = MustUse] | |
| 47 | #[attr = Inline(Hint)] | |
| 48 | unsafe fn unsafe_fn_extern() -> _ { to_reuse_functions::unsafe_fn_extern() } | |
| 49 | #[attr = MustUse {reason: "extern_fn_extern: some reason"}] | |
| 50 | #[attr = Inline(Hint)] | |
| 51 | extern "C" fn extern_fn_extern() | |
| 52 | -> _ { to_reuse_functions::extern_fn_extern() } | |
| 53 | #[attr = Inline(Hint)] | |
| 54 | const fn const_fn_extern() -> _ { to_reuse_functions::const_fn_extern() } | |
| 55 | #[attr = MustUse {reason: "some reason"}] | |
| 56 | #[attr = Inline(Hint)] | |
| 57 | async fn async_fn_extern() -> _ { to_reuse_functions::async_fn_extern() } | |
| 58 | ||
| 59 | mod recursive { | |
| 60 | // Check that `baz` inherit attribute from `foo` | |
| 61 | mod first { | |
| 62 | fn bar() { } | |
| 63 | #[attr = MustUse {reason: "some reason"}] | |
| 64 | #[attr = Inline(Hint)] | |
| 65 | fn foo() -> _ { bar() } | |
| 66 | #[attr = MustUse {reason: "some reason"}] | |
| 67 | #[attr = Inline(Hint)] | |
| 68 | fn baz() -> _ { foo() } | |
| 69 | } | |
| 70 | ||
| 71 | // Check that `baz` inherit attribute from `bar` | |
| 72 | mod second { | |
| 73 | #[attr = MustUse {reason: "some reason"}] | |
| 74 | fn bar() { } | |
| 75 | ||
| 76 | #[attr = MustUse {reason: "some reason"}] | |
| 77 | #[attr = Inline(Hint)] | |
| 78 | fn foo() -> _ { bar() } | |
| 79 | #[attr = MustUse {reason: "some reason"}] | |
| 80 | #[attr = Inline(Hint)] | |
| 81 | fn baz() -> _ { foo() } | |
| 82 | } | |
| 83 | ||
| 84 | // Check that `foo5` don't inherit attribute from `bar` | |
| 85 | // and inherit attribute from foo4, check that foo1, foo2 and foo3 | |
| 86 | // inherit attribute from bar | |
| 87 | mod third { | |
| 88 | #[attr = MustUse {reason: "some reason"}] | |
| 89 | fn bar() { } | |
| 90 | #[attr = MustUse {reason: "some reason"}] | |
| 91 | #[attr = Inline(Hint)] | |
| 92 | fn foo1() -> _ { bar() } | |
| 93 | #[attr = MustUse {reason: "some reason"}] | |
| 94 | #[attr = Inline(Hint)] | |
| 95 | fn foo2() -> _ { foo1() } | |
| 96 | #[attr = MustUse {reason: "some reason"}] | |
| 97 | #[attr = Inline(Hint)] | |
| 98 | fn foo3() -> _ { foo2() } | |
| 99 | #[attr = MustUse {reason: "foo4"}] | |
| 100 | #[attr = Inline(Hint)] | |
| 101 | fn foo4() -> _ { foo3() } | |
| 102 | #[attr = MustUse {reason: "foo4"}] | |
| 103 | #[attr = Inline(Hint)] | |
| 104 | fn foo5() -> _ { foo4() } | |
| 105 | } | |
| 106 | ||
| 107 | mod fourth { | |
| 108 | trait T { | |
| 109 | fn foo(&self, x: usize) -> usize { x + 1 } | |
| 110 | } | |
| 111 | ||
| 112 | struct X; | |
| 113 | impl T for X { } | |
| 114 | ||
| 115 | #[attr = MustUse {reason: "some reason"}] | |
| 116 | #[attr = Inline(Hint)] | |
| 117 | fn foo(self: _, arg1: _) -> _ { <X as T>::foo(self + 1, arg1) } | |
| 118 | #[attr = MustUse {reason: "some reason"}] | |
| 119 | #[attr = Inline(Hint)] | |
| 120 | fn bar(arg0: _, arg1: _) -> _ { foo(self + 1, arg1) } | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | fn main() { } |
tests/pretty/delegation/inherit-attributes.rs created+101| ... | ... | @@ -0,0 +1,101 @@ |
| 1 | //@ edition:2021 | |
| 2 | //@ aux-crate:to_reuse_functions=to-reuse-functions.rs | |
| 3 | //@ pretty-mode:hir | |
| 4 | //@ pretty-compare-only | |
| 5 | //@ pp-exact:inherit-attributes.pp | |
| 6 | ||
| 7 | #![allow(incomplete_features)] | |
| 8 | #![feature(fn_delegation)] | |
| 9 | ||
| 10 | extern crate to_reuse_functions; | |
| 11 | ||
| 12 | mod to_reuse { | |
| 13 | #[must_use = "foo: some reason"] | |
| 14 | #[cold] | |
| 15 | pub fn foo(x: usize) -> usize { | |
| 16 | x | |
| 17 | } | |
| 18 | ||
| 19 | #[must_use] | |
| 20 | #[cold] | |
| 21 | pub fn foo_no_reason(x: usize) -> usize { | |
| 22 | x | |
| 23 | } | |
| 24 | ||
| 25 | #[cold] | |
| 26 | #[deprecated] | |
| 27 | pub fn bar(x: usize) -> usize { | |
| 28 | x | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | #[deprecated] | |
| 33 | reuse to_reuse::foo as foo1 { | |
| 34 | self + 1 | |
| 35 | } | |
| 36 | ||
| 37 | reuse to_reuse::foo_no_reason { | |
| 38 | self + 1 | |
| 39 | } | |
| 40 | ||
| 41 | #[deprecated] | |
| 42 | #[must_use = "some reason"] | |
| 43 | reuse to_reuse::foo as foo2 { | |
| 44 | self + 1 | |
| 45 | } | |
| 46 | ||
| 47 | reuse to_reuse::bar; | |
| 48 | ||
| 49 | reuse to_reuse_functions::unsafe_fn_extern; | |
| 50 | reuse to_reuse_functions::extern_fn_extern; | |
| 51 | reuse to_reuse_functions::const_fn_extern; | |
| 52 | #[must_use = "some reason"] | |
| 53 | reuse to_reuse_functions::async_fn_extern; | |
| 54 | ||
| 55 | mod recursive { | |
| 56 | // Check that `baz` inherit attribute from `foo` | |
| 57 | mod first { | |
| 58 | fn bar() {} | |
| 59 | #[must_use = "some reason"] | |
| 60 | reuse bar as foo; | |
| 61 | reuse foo as baz; | |
| 62 | } | |
| 63 | ||
| 64 | // Check that `baz` inherit attribute from `bar` | |
| 65 | mod second { | |
| 66 | #[must_use = "some reason"] | |
| 67 | fn bar() {} | |
| 68 | ||
| 69 | reuse bar as foo; | |
| 70 | reuse foo as baz; | |
| 71 | } | |
| 72 | ||
| 73 | // Check that `foo5` don't inherit attribute from `bar` | |
| 74 | // and inherit attribute from foo4, check that foo1, foo2 and foo3 | |
| 75 | // inherit attribute from bar | |
| 76 | mod third { | |
| 77 | #[must_use = "some reason"] | |
| 78 | fn bar() {} | |
| 79 | reuse bar as foo1; | |
| 80 | reuse foo1 as foo2; | |
| 81 | reuse foo2 as foo3; | |
| 82 | #[must_use = "foo4"] | |
| 83 | reuse foo3 as foo4; | |
| 84 | reuse foo4 as foo5; | |
| 85 | } | |
| 86 | ||
| 87 | mod fourth { | |
| 88 | trait T { | |
| 89 | fn foo(&self, x: usize) -> usize { x + 1 } | |
| 90 | } | |
| 91 | ||
| 92 | struct X; | |
| 93 | impl T for X {} | |
| 94 | ||
| 95 | #[must_use = "some reason"] | |
| 96 | reuse <X as T>::foo { self + 1 } | |
| 97 | reuse foo as bar { self + 1 } | |
| 98 | } | |
| 99 | } | |
| 100 | ||
| 101 | fn main() {} |
tests/pretty/delegation/inline-attribute.pp created+92| ... | ... | @@ -0,0 +1,92 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:inline-attribute.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![attr = Feature([fn_delegation#0])] | |
| 7 | extern crate std; | |
| 8 | #[attr = PreludeImport] | |
| 9 | use ::std::prelude::rust_2015::*; | |
| 10 | ||
| 11 | mod to_reuse { | |
| 12 | fn foo(x: usize) -> usize { x } | |
| 13 | } | |
| 14 | ||
| 15 | // Check that #[inline(hint)] is added to foo reuse | |
| 16 | #[attr = Inline(Hint)] | |
| 17 | fn bar(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 18 | ||
| 19 | trait Trait { | |
| 20 | fn foo(&self) { } | |
| 21 | fn foo1(&self) { } | |
| 22 | fn foo2(&self) { } | |
| 23 | fn foo3(&self) { } | |
| 24 | fn foo4(&self) { } | |
| 25 | } | |
| 26 | ||
| 27 | impl Trait for u8 { } | |
| 28 | ||
| 29 | struct S(u8); | |
| 30 | ||
| 31 | mod to_import { | |
| 32 | fn check(arg: &'_ u8) -> &'_ u8 { arg } | |
| 33 | } | |
| 34 | ||
| 35 | impl Trait for S { | |
| 36 | // Check that #[inline(hint)] is added to foo reuse | |
| 37 | #[attr = Inline(Hint)] | |
| 38 | fn foo(self: _) | |
| 39 | -> | |
| 40 | _ { | |
| 41 | // Check that #[inline(hint)] is added to foo0 reuse inside another reuse | |
| 42 | #[attr = Inline(Hint)] | |
| 43 | fn foo0(arg0: _) -> _ { to_reuse::foo(self + 1) } | |
| 44 | ||
| 45 | // Check that #[inline(hint)] is added when other attributes present in inner reuse | |
| 46 | #[attr = Cold] | |
| 47 | #[attr = MustUse] | |
| 48 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 49 | #[attr = Inline(Hint)] | |
| 50 | fn foo1(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 51 | ||
| 52 | // Check that #[inline(never)] is preserved in inner reuse | |
| 53 | #[attr = Inline(Never)] | |
| 54 | fn foo2(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 55 | ||
| 56 | // Check that #[inline(always)] is preserved in inner reuse | |
| 57 | #[attr = Inline(Always)] | |
| 58 | fn foo3(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 59 | ||
| 60 | // Check that #[inline(never)] is preserved when there are other attributes in inner reuse | |
| 61 | #[attr = Cold] | |
| 62 | #[attr = MustUse] | |
| 63 | #[attr = Inline(Never)] | |
| 64 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 65 | fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) } | |
| 66 | Trait::foo(self) | |
| 67 | } | |
| 68 | ||
| 69 | // Check that #[inline(hint)] is added when there are other attributes present in trait reuse | |
| 70 | #[attr = Cold] | |
| 71 | #[attr = MustUse] | |
| 72 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 73 | #[attr = Inline(Hint)] | |
| 74 | fn foo1(self: _) -> _ { Trait::foo1(self.0) } | |
| 75 | ||
| 76 | // Check that #[inline(never)] is preserved in trait reuse | |
| 77 | #[attr = Inline(Never)] | |
| 78 | fn foo2(self: _) -> _ { Trait::foo2(self.0) } | |
| 79 | ||
| 80 | // Check that #[inline(always)] is preserved in trait reuse | |
| 81 | #[attr = Inline(Always)] | |
| 82 | fn foo3(self: _) -> _ { Trait::foo3(self.0) } | |
| 83 | ||
| 84 | // Check that #[inline(never)] is preserved when there are other attributes in trait reuse | |
| 85 | #[attr = Cold] | |
| 86 | #[attr = MustUse] | |
| 87 | #[attr = Inline(Never)] | |
| 88 | #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] | |
| 89 | fn foo4(self: _) -> _ { Trait::foo4(self.0) } | |
| 90 | } | |
| 91 | ||
| 92 | fn main() { } |
tests/pretty/delegation/inline-attribute.rs created+104| ... | ... | @@ -0,0 +1,104 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:inline-attribute.pp | |
| 4 | ||
| 5 | #![allow(incomplete_features)] | |
| 6 | #![feature(fn_delegation)] | |
| 7 | ||
| 8 | mod to_reuse { | |
| 9 | pub fn foo(x: usize) -> usize { | |
| 10 | x | |
| 11 | } | |
| 12 | } | |
| 13 | ||
| 14 | // Check that #[inline(hint)] is added to foo reuse | |
| 15 | reuse to_reuse::foo as bar { | |
| 16 | self + 1 | |
| 17 | } | |
| 18 | ||
| 19 | trait Trait { | |
| 20 | fn foo(&self) {} | |
| 21 | fn foo1(&self) {} | |
| 22 | fn foo2(&self) {} | |
| 23 | fn foo3(&self) {} | |
| 24 | fn foo4(&self) {} | |
| 25 | } | |
| 26 | ||
| 27 | impl Trait for u8 {} | |
| 28 | ||
| 29 | struct S(u8); | |
| 30 | ||
| 31 | mod to_import { | |
| 32 | pub fn check(arg: &u8) -> &u8 { arg } | |
| 33 | } | |
| 34 | ||
| 35 | impl Trait for S { | |
| 36 | // Check that #[inline(hint)] is added to foo reuse | |
| 37 | reuse Trait::foo { | |
| 38 | // Check that #[inline(hint)] is added to foo0 reuse inside another reuse | |
| 39 | reuse to_reuse::foo as foo0 { | |
| 40 | self + 1 | |
| 41 | } | |
| 42 | ||
| 43 | // Check that #[inline(hint)] is added when other attributes present in inner reuse | |
| 44 | #[cold] | |
| 45 | #[must_use] | |
| 46 | #[deprecated] | |
| 47 | reuse to_reuse::foo as foo1 { | |
| 48 | self / 2 | |
| 49 | } | |
| 50 | ||
| 51 | // Check that #[inline(never)] is preserved in inner reuse | |
| 52 | #[inline(never)] | |
| 53 | reuse to_reuse::foo as foo2 { | |
| 54 | self / 2 | |
| 55 | } | |
| 56 | ||
| 57 | // Check that #[inline(always)] is preserved in inner reuse | |
| 58 | #[inline(always)] | |
| 59 | reuse to_reuse::foo as foo3 { | |
| 60 | self / 2 | |
| 61 | } | |
| 62 | ||
| 63 | // Check that #[inline(never)] is preserved when there are other attributes in inner reuse | |
| 64 | #[cold] | |
| 65 | #[must_use] | |
| 66 | #[inline(never)] | |
| 67 | #[deprecated] | |
| 68 | reuse to_reuse::foo as foo4 { | |
| 69 | self / 2 | |
| 70 | } | |
| 71 | } | |
| 72 | ||
| 73 | // Check that #[inline(hint)] is added when there are other attributes present in trait reuse | |
| 74 | #[cold] | |
| 75 | #[must_use] | |
| 76 | #[deprecated] | |
| 77 | reuse Trait::foo1 { | |
| 78 | self.0 | |
| 79 | } | |
| 80 | ||
| 81 | // Check that #[inline(never)] is preserved in trait reuse | |
| 82 | #[inline(never)] | |
| 83 | reuse Trait::foo2 { | |
| 84 | self.0 | |
| 85 | } | |
| 86 | ||
| 87 | // Check that #[inline(always)] is preserved in trait reuse | |
| 88 | #[inline(always)] | |
| 89 | reuse Trait::foo3 { | |
| 90 | self.0 | |
| 91 | } | |
| 92 | ||
| 93 | // Check that #[inline(never)] is preserved when there are other attributes in trait reuse | |
| 94 | #[cold] | |
| 95 | #[must_use] | |
| 96 | #[inline(never)] | |
| 97 | #[deprecated] | |
| 98 | reuse Trait::foo4 { | |
| 99 | self.0 | |
| 100 | } | |
| 101 | } | |
| 102 | ||
| 103 | fn main() { | |
| 104 | } |
tests/pretty/delegation/self-rename.pp created+58| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | #![attr = Feature([fn_delegation#0])] | |
| 2 | extern crate std; | |
| 3 | #[attr = PreludeImport] | |
| 4 | use ::std::prelude::rust_2015::*; | |
| 5 | //@ pretty-compare-only | |
| 6 | //@ pretty-mode:hir | |
| 7 | //@ pp-exact:self-rename.pp | |
| 8 | ||
| 9 | ||
| 10 | trait Trait<'a, A, const B: bool> { | |
| 11 | fn foo<'b, const B2: bool, T, U, | |
| 12 | impl FnOnce() -> usize>(&self, f: impl FnOnce() -> usize) -> usize | |
| 13 | where impl FnOnce() -> usize: FnOnce() -> usize { f() + 1 } | |
| 14 | } | |
| 15 | ||
| 16 | struct X; | |
| 17 | impl <'a, A, const B: bool> Trait<'a, A, B> for X { } | |
| 18 | ||
| 19 | #[attr = Inline(Hint)] | |
| 20 | fn foo<'a, Self, A, const B: _, const B2: _, T, U, | |
| 21 | impl FnOnce() -> usize>(self: _, arg1: _) -> _ where | |
| 22 | 'a:'a { <Self as Trait::<'a, A, B>>::foo::<B2, T, U>(self, arg1) } | |
| 23 | #[attr = Inline(Hint)] | |
| 24 | fn bar<Self, impl FnOnce() -> usize>(self: _, arg1: _) | |
| 25 | -> | |
| 26 | _ { | |
| 27 | <Self as Trait::<'static, (), true>>::foo::<true, (), ()>(self, arg1) | |
| 28 | } | |
| 29 | ||
| 30 | #[attr = Inline(Hint)] | |
| 31 | fn foo2<'a, This, A, const B: _, const B2: _, T, U, | |
| 32 | impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where | |
| 33 | 'a:'a { foo::<'a, This, A, B, B2, T, U>(arg0, arg1) } | |
| 34 | #[attr = Inline(Hint)] | |
| 35 | fn bar2<This, impl FnOnce() -> usize>(arg0: _, arg1: _) | |
| 36 | -> _ { bar::<This>(arg0, arg1) } | |
| 37 | ||
| 38 | trait Trait2 { | |
| 39 | #[attr = Inline(Hint)] | |
| 40 | fn foo3<'a, This, A, const B: _, const B2: _, T, U, | |
| 41 | impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where | |
| 42 | 'a:'a { foo2::<'a, This, A, B, B2, T, U>(arg0, arg1) } | |
| 43 | #[attr = Inline(Hint)] | |
| 44 | fn bar3<This, impl FnOnce() -> usize>(arg0: _, arg1: _) | |
| 45 | -> _ { bar2::<This>(arg0, arg1) } | |
| 46 | } | |
| 47 | ||
| 48 | impl Trait2 for () { } | |
| 49 | ||
| 50 | #[attr = Inline(Hint)] | |
| 51 | fn foo4<'a, This, A, const B: _, const B2: _, T, U, | |
| 52 | impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where | |
| 53 | 'a:'a { <() as Trait2>::foo3::<'a, This, A, B, B2, T, U>(arg0, arg1) } | |
| 54 | #[attr = Inline(Hint)] | |
| 55 | fn bar4<This, impl FnOnce() -> usize>(arg0: _, arg1: _) | |
| 56 | -> _ { <() as Trait2>::bar3::<This>(arg0, arg1) } | |
| 57 | ||
| 58 | fn main() { } |
tests/pretty/delegation/self-rename.rs created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | //@ pretty-compare-only | |
| 2 | //@ pretty-mode:hir | |
| 3 | //@ pp-exact:self-rename.pp | |
| 4 | ||
| 5 | #![feature(fn_delegation)] | |
| 6 | ||
| 7 | trait Trait<'a, A, const B: bool> { | |
| 8 | fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { | |
| 9 | f() + 1 | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | struct X; | |
| 14 | impl<'a, A, const B: bool> Trait<'a, A, B> for X {} | |
| 15 | ||
| 16 | reuse Trait::foo; | |
| 17 | reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar; | |
| 18 | ||
| 19 | reuse foo as foo2; | |
| 20 | reuse bar as bar2; | |
| 21 | ||
| 22 | trait Trait2 { | |
| 23 | reuse foo2 as foo3; | |
| 24 | reuse bar2 as bar3; | |
| 25 | } | |
| 26 | ||
| 27 | impl Trait2 for () {} | |
| 28 | ||
| 29 | reuse <() as Trait2>::foo3 as foo4; | |
| 30 | reuse <() as Trait2>::bar3 as bar4; | |
| 31 | ||
| 32 | fn main() {} |
tests/ui/attributes/may_dangle.rs+5-5| ... | ... | @@ -12,7 +12,7 @@ unsafe impl<'a, #[may_dangle] T, const N: usize> NotDrop for Implee2<'a, T, N> { |
| 12 | 12 | //~^ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl |
| 13 | 13 | |
| 14 | 14 | unsafe impl<'a, T, #[may_dangle] const N: usize> Drop for Implee1<'a, T, N> { |
| 15 | //~^ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 15 | //~^ ERROR attribute cannot be used on | |
| 16 | 16 | fn drop(&mut self) {} |
| 17 | 17 | } |
| 18 | 18 | |
| ... | ... | @@ -39,15 +39,15 @@ mod fake { |
| 39 | 39 | } |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | #[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 42 | #[may_dangle] //~ ERROR attribute cannot be used on | |
| 43 | 43 | struct Dangling; |
| 44 | 44 | |
| 45 | #[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 45 | #[may_dangle] //~ ERROR attribute cannot be used on | |
| 46 | 46 | impl NotDrop for () { |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | #[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 49 | #[may_dangle] //~ ERROR attribute cannot be used on | |
| 50 | 50 | fn main() { |
| 51 | #[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 51 | #[may_dangle] //~ ERROR attribute cannot be used on | |
| 52 | 52 | let () = (); |
| 53 | 53 | } |
tests/ui/attributes/may_dangle.stderr+27-17| ... | ... | @@ -1,44 +1,54 @@ |
| 1 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 2 | --> $DIR/may_dangle.rs:8:13 | |
| 3 | | | |
| 4 | LL | unsafe impl<#[may_dangle] 'a, T, const N: usize> NotDrop for Implee1<'a, T, N> {} | |
| 5 | | ^^^^^^^^^^^^^ | |
| 6 | ||
| 7 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 8 | --> $DIR/may_dangle.rs:11:17 | |
| 9 | | | |
| 10 | LL | unsafe impl<'a, #[may_dangle] T, const N: usize> NotDrop for Implee2<'a, T, N> {} | |
| 11 | | ^^^^^^^^^^^^^ | |
| 12 | ||
| 13 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 1 | error: `#[may_dangle]` attribute cannot be used on const parameters | |
| 14 | 2 | --> $DIR/may_dangle.rs:14:20 |
| 15 | 3 | | |
| 16 | 4 | LL | unsafe impl<'a, T, #[may_dangle] const N: usize> Drop for Implee1<'a, T, N> { |
| 17 | 5 | | ^^^^^^^^^^^^^ |
| 6 | | | |
| 7 | = help: `#[may_dangle]` can be applied to lifetime parameters and type parameters | |
| 18 | 8 | |
| 19 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 9 | error: `#[may_dangle]` attribute cannot be used on structs | |
| 20 | 10 | --> $DIR/may_dangle.rs:42:1 |
| 21 | 11 | | |
| 22 | 12 | LL | #[may_dangle] |
| 23 | 13 | | ^^^^^^^^^^^^^ |
| 14 | | | |
| 15 | = help: `#[may_dangle]` can be applied to lifetime parameters and type parameters | |
| 24 | 16 | |
| 25 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 17 | error: `#[may_dangle]` attribute cannot be used on trait impl blocks | |
| 26 | 18 | --> $DIR/may_dangle.rs:45:1 |
| 27 | 19 | | |
| 28 | 20 | LL | #[may_dangle] |
| 29 | 21 | | ^^^^^^^^^^^^^ |
| 22 | | | |
| 23 | = help: `#[may_dangle]` can be applied to lifetime parameters and type parameters | |
| 30 | 24 | |
| 31 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 25 | error: `#[may_dangle]` attribute cannot be used on functions | |
| 32 | 26 | --> $DIR/may_dangle.rs:49:1 |
| 33 | 27 | | |
| 34 | 28 | LL | #[may_dangle] |
| 35 | 29 | | ^^^^^^^^^^^^^ |
| 30 | | | |
| 31 | = help: `#[may_dangle]` can be applied to lifetime parameters and type parameters | |
| 36 | 32 | |
| 37 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 33 | error: `#[may_dangle]` attribute cannot be used on statements | |
| 38 | 34 | --> $DIR/may_dangle.rs:51:5 |
| 39 | 35 | | |
| 40 | 36 | LL | #[may_dangle] |
| 41 | 37 | | ^^^^^^^^^^^^^ |
| 38 | | | |
| 39 | = help: `#[may_dangle]` can be applied to lifetime parameters and type parameters | |
| 40 | ||
| 41 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 42 | --> $DIR/may_dangle.rs:8:13 | |
| 43 | | | |
| 44 | LL | unsafe impl<#[may_dangle] 'a, T, const N: usize> NotDrop for Implee1<'a, T, N> {} | |
| 45 | | ^^^^^^^^^^^^^ | |
| 46 | ||
| 47 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl | |
| 48 | --> $DIR/may_dangle.rs:11:17 | |
| 49 | | | |
| 50 | LL | unsafe impl<'a, #[may_dangle] T, const N: usize> NotDrop for Implee2<'a, T, N> {} | |
| 51 | | ^^^^^^^^^^^^^ | |
| 42 | 52 | |
| 43 | 53 | error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl |
| 44 | 54 | --> $DIR/may_dangle.rs:36:17 |
tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.rs created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | #![feature(min_generic_const_args)] | |
| 2 | ||
| 3 | trait A<T> {} | |
| 4 | trait Trait<const N: usize> {} | |
| 5 | ||
| 6 | impl A<[usize; fn_item]> for () {} | |
| 7 | ||
| 8 | fn fn_item(_: impl Trait<usize>) {} | |
| 9 | //~^ ERROR: type provided when a constant was expected | |
| 10 | ||
| 11 | fn main() {} |
tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.stderr created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | error[E0747]: type provided when a constant was expected | |
| 2 | --> $DIR/synth-gen-arg-ice-158152.rs:8:26 | |
| 3 | | | |
| 4 | LL | fn fn_item(_: impl Trait<usize>) {} | |
| 5 | | ^^^^^ | |
| 6 | | | |
| 7 | help: if this generic argument was intended as a const parameter, surround it with braces | |
| 8 | | | |
| 9 | LL | fn fn_item(_: impl Trait<{ usize }>) {} | |
| 10 | | + + | |
| 11 | ||
| 12 | error: aborting due to 1 previous error | |
| 13 | ||
| 14 | For more information about this error, try `rustc --explain E0747`. |
tests/ui/delegation/generics/infer-defaults.rs created+124| ... | ... | @@ -0,0 +1,124 @@ |
| 1 | #![feature(fn_delegation)] | |
| 2 | ||
| 3 | mod free_to_trait { | |
| 4 | trait Trait<'a, XX, Y, T = (), const N: usize = 2> { | |
| 5 | fn foo<A, B>(&self, t: (T, A, B), slice: &[usize; N]) {} | |
| 6 | } | |
| 7 | ||
| 8 | struct X; | |
| 9 | impl<XX, Y, T, const N: usize> Trait<'_, XX, Y, T, N> for X {} | |
| 10 | ||
| 11 | // When infer is specified for default parameter the generic param is generated. | |
| 12 | reuse Trait::<'_, _, _, _, _>::foo as foo; | |
| 13 | // When default params are omitted they are not generated but used in signature inheritance. | |
| 14 | reuse Trait::<'_, _, _>::foo as bar; | |
| 15 | ||
| 16 | // Check with user specified args in child: | |
| 17 | // When infer is specified for default parameter the generic param is generated. | |
| 18 | reuse Trait::<'_, _, _, _, _>::foo::<(), _> as foo1; | |
| 19 | // When default params are omitted they are not generated but used in signature inheritance. | |
| 20 | reuse Trait::<'_, _, _>::foo::<_, ()> as bar1; | |
| 21 | ||
| 22 | // Check with explicit self type. | |
| 23 | reuse <X as Trait::<'_, _, _, _, _>>::foo as foo2; | |
| 24 | reuse <X as Trait::<'_, _, _>>::foo as bar2; | |
| 25 | ||
| 26 | reuse <X as Trait::<'_, _, _, _, _>>::foo::<(), _> as foo3; | |
| 27 | reuse <X as Trait::<'_, _, _>>::foo::<_, ()> as bar3; | |
| 28 | ||
| 29 | fn check() { | |
| 30 | foo::<'static, X, (), (), (), 1, (), ()>(&X, ((), (), ()), &[1]); | |
| 31 | bar::<'static, X, (), (), (), ()>(&X, ((), (), ()), &[1, 2]); | |
| 32 | ||
| 33 | foo1::<'static, X, (), (), (), 2, ()>(&X, ((), (), ()), &[1, 2]); | |
| 34 | bar1::<'static, X, (), (), ()>(&X, ((), (), ()), &[1, 2]); | |
| 35 | ||
| 36 | foo2::<'static, (), (), (), 3, (), ()>(&X, ((), (), ()), &[1, 2, 3]); | |
| 37 | bar2::<'static, (), (), (), ()>(&X, ((), (), ()), &[1, 2]); | |
| 38 | ||
| 39 | foo3::<'static, (), (), (), 4, ()>(&X, ((), (), ()), &[1, 2, 3, 4]); | |
| 40 | bar3::<'static, (), (), ()>(&X, ((), (), ()), &[1, 2]); | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | mod trait_to_trait { | |
| 45 | trait Trait<'a, X, Y, T = (), const N: usize = 2> { | |
| 46 | fn foo(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 47 | fn bar(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 48 | } | |
| 49 | ||
| 50 | trait Trait2<'a, X, Y>: Trait<'a, X, Y> { | |
| 51 | // Default params are generated as usual generics as infers are specified. | |
| 52 | reuse Trait::<'a, X, Y, _, _>::foo; | |
| 53 | //~^ ERROR: the trait bound `Self: trait_to_trait::Trait<'a, X, Y, T, N>` is not satisfied | |
| 54 | ||
| 55 | // Default params are not generated, as they are not specified. | |
| 56 | reuse Trait::<'a, X, Y>::foo as bar; | |
| 57 | } | |
| 58 | ||
| 59 | impl Trait<'static, (), ()> for () {} | |
| 60 | impl Trait2<'static, (), ()> for () {} | |
| 61 | ||
| 62 | fn check() { | |
| 63 | Trait2::<'static, (), ()>::foo::<(), 1>(&(), ((), (), ()), &[1]); | |
| 64 | Trait2::<'static, (), ()>::bar(&(), ((), (), ()), &[1, 2]); | |
| 65 | } | |
| 66 | } | |
| 67 | ||
| 68 | mod trait_impl_to_trait { | |
| 69 | trait Trait<'a, X, Y, T = (), const N: usize = 2> { | |
| 70 | fn foo(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 71 | fn bar(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 72 | } | |
| 73 | ||
| 74 | struct S; | |
| 75 | impl<X, Y> Trait<'_, X, Y> for S {} | |
| 76 | ||
| 77 | struct W(S); | |
| 78 | impl<X, Y> Trait<'_, X, Y> for W { | |
| 79 | // Generics of both methods match generics of their signature | |
| 80 | // functions in `Trait` declaration, no matter specified infers. | |
| 81 | reuse Trait::<'static, X, Y>::foo { self.0 } | |
| 82 | reuse Trait::<'static, X, Y, _, _>::foo as bar { self.0 } | |
| 83 | } | |
| 84 | ||
| 85 | fn check() { | |
| 86 | W(S).foo(((), (), ()), &[1, 2]); | |
| 87 | W(S).foo::<1, 2, 3>(((), (), ()), &[1, 2]); | |
| 88 | //~^ ERROR: method takes 0 generic arguments but 3 generic arguments were supplied | |
| 89 | ||
| 90 | W(S).bar(((), (), ()), &[1]); | |
| 91 | //~^ ERROR: mismatched types | |
| 92 | W(S).bar::<((), ()), 0>(((), (), ()), &[1, 2]); | |
| 93 | //~^ ERROR: method takes 0 generic arguments but 2 generic arguments were supplied | |
| 94 | ||
| 95 | W(S).bar(((), (), ()), &[1, 2]); | |
| 96 | } | |
| 97 | } | |
| 98 | ||
| 99 | mod inherent_impl_to_trait { | |
| 100 | trait Trait<'a, X, Y, T = (), const N: usize = 2> { | |
| 101 | fn foo(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 102 | } | |
| 103 | ||
| 104 | struct S<T>(T); | |
| 105 | ||
| 106 | impl<T: Trait<'static, (), ()>> S<T> { | |
| 107 | // Default params are not generated, as they are not specified. | |
| 108 | reuse Trait::<'static, (), ()>::foo { self.0 } | |
| 109 | ||
| 110 | // Default params are generated as usual generics as infers are specified. | |
| 111 | reuse Trait::<'static, (), (), _, _>::foo as bar { self.0 } | |
| 112 | //~^ ERROR: the trait bound `T: inherent_impl_to_trait::Trait<'static, (), (), T, N>` is not satisfied | |
| 113 | } | |
| 114 | ||
| 115 | impl Trait<'static, (), ()> for () {} | |
| 116 | ||
| 117 | fn check() { | |
| 118 | S(()).foo(((), (), ()), &[1, 2]); | |
| 119 | S(()).bar(((), (), ()), &[1, 2]); | |
| 120 | S(()).bar::<usize, 4>((1, 2, 3), &[1, 2, 3, 4]); | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | fn main() {} |
tests/ui/delegation/generics/infer-defaults.stderr created+70| ... | ... | @@ -0,0 +1,70 @@ |
| 1 | error[E0277]: the trait bound `Self: trait_to_trait::Trait<'a, X, Y, T, N>` is not satisfied | |
| 2 | --> $DIR/infer-defaults.rs:52:40 | |
| 3 | | | |
| 4 | LL | reuse Trait::<'a, X, Y, _, _>::foo; | |
| 5 | | ^^^ the trait `trait_to_trait::Trait<'a, X, Y, T, N>` is not implemented for `Self` | |
| 6 | | | |
| 7 | help: consider further restricting `Self` | |
| 8 | | | |
| 9 | LL | reuse Trait::<'a, X, Y, _, _>::foo Self: trait_to_trait::Trait<'a, X, Y, T, N>; | |
| 10 | | +++++++++++++++++++++++++++++++++++++++++++ | |
| 11 | ||
| 12 | error[E0107]: method takes 0 generic arguments but 3 generic arguments were supplied | |
| 13 | --> $DIR/infer-defaults.rs:87:14 | |
| 14 | | | |
| 15 | LL | W(S).foo::<1, 2, 3>(((), (), ()), &[1, 2]); | |
| 16 | | ^^^----------- help: remove the unnecessary generics | |
| 17 | | | | |
| 18 | | expected 0 generic arguments | |
| 19 | | | |
| 20 | note: method defined here, with 0 generic parameters | |
| 21 | --> $DIR/infer-defaults.rs:70:12 | |
| 22 | | | |
| 23 | LL | fn foo(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 24 | | ^^^ | |
| 25 | ||
| 26 | error[E0308]: mismatched types | |
| 27 | --> $DIR/infer-defaults.rs:90:32 | |
| 28 | | | |
| 29 | LL | W(S).bar(((), (), ()), &[1]); | |
| 30 | | --- ^^^^ expected an array with a size of 2, found one with a size of 1 | |
| 31 | | | | |
| 32 | | arguments to this method are incorrect | |
| 33 | | | |
| 34 | note: method defined here | |
| 35 | --> $DIR/infer-defaults.rs:71:12 | |
| 36 | | | |
| 37 | LL | fn bar(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 38 | | ^^^ ------------------ | |
| 39 | ||
| 40 | error[E0107]: method takes 0 generic arguments but 2 generic arguments were supplied | |
| 41 | --> $DIR/infer-defaults.rs:92:14 | |
| 42 | | | |
| 43 | LL | W(S).bar::<((), ()), 0>(((), (), ()), &[1, 2]); | |
| 44 | | ^^^--------------- help: remove the unnecessary generics | |
| 45 | | | | |
| 46 | | expected 0 generic arguments | |
| 47 | | | |
| 48 | note: method defined here, with 0 generic parameters | |
| 49 | --> $DIR/infer-defaults.rs:71:12 | |
| 50 | | | |
| 51 | LL | fn bar(&self, t: (T, T, T), slice: &[usize; N]) {} | |
| 52 | | ^^^ | |
| 53 | ||
| 54 | error[E0277]: the trait bound `T: inherent_impl_to_trait::Trait<'static, (), (), T, N>` is not satisfied | |
| 55 | --> $DIR/infer-defaults.rs:111:60 | |
| 56 | | | |
| 57 | LL | reuse Trait::<'static, (), (), _, _>::foo as bar { self.0 } | |
| 58 | | --- ^^^^^^ the trait `inherent_impl_to_trait::Trait<'static, (), (), T, N>` is not implemented for `T` | |
| 59 | | | | |
| 60 | | required by a bound introduced by this call | |
| 61 | | | |
| 62 | help: consider restricting type parameter `T` with trait `Trait` | |
| 63 | | | |
| 64 | LL | reuse Trait::<'static, (), (), _, _>::foo inherent_impl_to_trait::Trait<'static, (), (), T, N> as bar { self.0 } | |
| 65 | | ++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 66 | ||
| 67 | error: aborting due to 5 previous errors | |
| 68 | ||
| 69 | Some errors have detailed explanations: E0107, E0277, E0308. | |
| 70 | For more information about an error, try `rustc --explain E0107`. |
tests/ui/macros/deref-raw-pointer-issue-158158.rs created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | struct Demo { | |
| 2 | val: u32, | |
| 3 | } | |
| 4 | ||
| 5 | macro_rules! as_ptr { | |
| 6 | ($d:expr) => { | |
| 7 | &mut $d as *mut Demo | |
| 8 | }; | |
| 9 | } | |
| 10 | ||
| 11 | macro_rules! get_value { | |
| 12 | ($d:expr) => { | |
| 13 | as_ptr!($d).val | |
| 14 | //~^ ERROR no field `val` on type `*mut Demo` | |
| 15 | } | |
| 16 | } | |
| 17 | ||
| 18 | fn main() { | |
| 19 | let mut d = Demo { val: 123 }; | |
| 20 | let _ = get_value!(d); | |
| 21 | } |
tests/ui/macros/deref-raw-pointer-issue-158158.stderr created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | error[E0609]: no field `val` on type `*mut Demo` | |
| 2 | --> $DIR/deref-raw-pointer-issue-158158.rs:13:21 | |
| 3 | | | |
| 4 | LL | as_ptr!($d).val | |
| 5 | | ^^^ unknown field | |
| 6 | ... | |
| 7 | LL | let _ = get_value!(d); | |
| 8 | | ------------- in this macro invocation | |
| 9 | | | |
| 10 | = note: this error originates in the macro `get_value` (in Nightly builds, run with -Z macro-backtrace for more info) | |
| 11 | ||
| 12 | error: aborting due to 1 previous error | |
| 13 | ||
| 14 | For more information about this error, try `rustc --explain E0609`. |