diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e2424e7d7ad90..169e0ef571516 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2058,7 +2058,7 @@ pub struct InlineAsm { pub template: Vec, pub template_strs: Box<[(Symbol, Option, Span)]>, pub operands: Vec<(InlineAsmOperand, Span)>, - pub clobber_abi: Option<(Symbol, Span)>, + pub clobber_abis: Vec<(Symbol, Span)>, pub options: InlineAsmOptions, pub line_spans: Vec, } @@ -2707,7 +2707,7 @@ pub enum ItemKind { /// E.g., `extern {}` or `extern "C" {}`. ForeignMod(ForeignMod), /// Module-level inline assembly (from `global_asm!()`). - GlobalAsm(InlineAsm), + GlobalAsm(Box), /// A type alias (`type`). /// /// E.g., `type Foo = Bar;`. diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 957b14f348729..198e4fa99ea3a 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -2,6 +2,7 @@ use super::LoweringContext; use rustc_ast::*; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_span::{Span, Symbol}; @@ -27,22 +28,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .emit(); } - let mut clobber_abi = None; + let mut clobber_abis = FxHashMap::default(); if let Some(asm_arch) = asm_arch { - if let Some((abi_name, abi_span)) = asm.clobber_abi { - match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) { - Ok(abi) => clobber_abi = Some((abi, abi_span)), + for (abi_name, abi_span) in &asm.clobber_abis { + match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) { + Ok(abi) => { + // If the abi was already in the list, emit an error + match clobber_abis.get(&abi) { + Some((prev_name, prev_sp)) => { + let mut err = self.sess.struct_span_err( + *abi_span, + &format!("`{}` ABI specified multiple times", prev_name), + ); + err.span_label(*prev_sp, "previously specified here"); + + // Multiple different abi names may actually be the same ABI + // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI + let source_map = self.sess.source_map(); + if source_map.span_to_snippet(*prev_sp) + != source_map.span_to_snippet(*abi_span) + { + err.note("these ABIs are equivalent on the current target"); + } + + err.emit(); + } + None => { + clobber_abis.insert(abi, (abi_name, *abi_span)); + } + } + } Err(&[]) => { self.sess .struct_span_err( - abi_span, + *abi_span, "`clobber_abi` is not supported on this target", ) .emit(); } Err(supported_abis) => { let mut err = - self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`"); + self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); let mut abis = format!("`{}`", supported_abis[0]); for m in &supported_abis[1..] { let _ = write!(abis, ", `{}`", m); @@ -308,8 +334,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If a clobber_abi is specified, add the necessary clobbers to the // operands list. - if let Some((abi, abi_span)) = clobber_abi { + let mut clobbered = FxHashSet::default(); + for (abi, (_, abi_span)) in clobber_abis { for &clobber in abi.clobbered_regs() { + // Don't emit a clobber for a register already clobbered + if clobbered.contains(&clobber) { + continue; + } + let mut output_used = false; clobber.overlapping_regs(|reg| { if used_output_regs.contains_key(®) { @@ -326,6 +358,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }, self.lower_span(abi_span), )); + clobbered.insert(clobber); } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c24882086e12d..e83ce6b021474 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2199,8 +2199,8 @@ impl<'a> State<'a> { let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))]; args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o))); - if let Some((abi, _)) = asm.clobber_abi { - args.push(AsmArg::ClobberAbi(abi)); + for (abi, _) in &asm.clobber_abis { + args.push(AsmArg::ClobberAbi(*abi)); } if !asm.options.is_empty() { args.push(AsmArg::Options(asm.options)); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index c032364c008f3..0ac3ce10dc51b 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -19,7 +19,7 @@ struct AsmArgs { operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxHashMap, reg_args: FxHashSet, - clobber_abi: Option<(Symbol, Span)>, + clobber_abis: Vec<(Symbol, Span)>, options: ast::InlineAsmOptions, options_spans: Vec, } @@ -64,7 +64,7 @@ fn parse_args<'a>( operands: vec![], named_args: FxHashMap::default(), reg_args: FxHashSet::default(), - clobber_abi: None, + clobber_abis: Vec::new(), options: ast::InlineAsmOptions::empty(), options_spans: vec![], }; @@ -210,9 +210,9 @@ fn parse_args<'a>( .span_labels(args.options_spans.clone(), "previous options") .span_label(span, "argument") .emit(); - } else if let Some((_, abi_span)) = args.clobber_abi { + } else if let Some((_, abi_span)) = args.clobber_abis.last() { ecx.struct_span_err(span, "arguments are not allowed after clobber_abi") - .span_label(abi_span, "clobber_abi") + .span_label(*abi_span, "clobber_abi") .span_label(span, "argument") .emit(); } @@ -322,10 +322,13 @@ fn parse_args<'a>( // Bail out now since this is likely to confuse MIR return Err(err); } - if let Some((_, abi_span)) = args.clobber_abi { + + if args.clobber_abis.len() > 0 { if is_global_asm { - let err = - ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`"); + let err = ecx.struct_span_err( + args.clobber_abis.iter().map(|(_, span)| *span).collect::>(), + "`clobber_abi` cannot be used with `global_asm!`", + ); // Bail out now since this is likely to confuse later stages return Err(err); @@ -335,7 +338,10 @@ fn parse_args<'a>( regclass_outputs.clone(), "asm with `clobber_abi` must specify explicit registers for outputs", ) - .span_label(abi_span, "clobber_abi") + .span_labels( + args.clobber_abis.iter().map(|(_, span)| *span).collect::>(), + "clobber_abi", + ) .span_labels(regclass_outputs, "generic outputs") .emit(); } @@ -439,37 +445,61 @@ fn parse_clobber_abi<'a>( p.expect(&token::OpenDelim(token::DelimToken::Paren))?; - let clobber_abi = match p.parse_str_lit() { - Ok(str_lit) => str_lit.symbol_unescaped, - Err(opt_lit) => { - let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); - err.span_label(span, "not a string literal"); - return Err(err); - } - }; + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + let err = p.sess.span_diagnostic.struct_span_err( + p.token.span, + "at least one abi must be provided as an argument to `clobber_abi`", + ); + return Err(err); + } - p.expect(&token::CloseDelim(token::DelimToken::Paren))?; + let mut new_abis = Vec::new(); + loop { + match p.parse_str_lit() { + Ok(str_lit) => { + new_abis.push((str_lit.symbol_unescaped, str_lit.span)); + } + Err(opt_lit) => { + // If the non-string literal is a closing paren then it's the end of the list and is fine + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + break; + } + let span = opt_lit.map_or(p.token.span, |lit| lit.span); + let mut err = + p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); + err.span_label(span, "not a string literal"); + return Err(err); + } + }; - let new_span = span_start.to(p.prev_token.span); + // Allow trailing commas + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + break; + } + p.expect(&token::Comma)?; + } - if let Some((_, prev_span)) = args.clobber_abi { - let mut err = p - .sess - .span_diagnostic - .struct_span_err(new_span, "clobber_abi specified multiple times"); - err.span_label(prev_span, "clobber_abi previously specified here"); - return Err(err); - } else if !args.options_spans.is_empty() { + let full_span = span_start.to(p.prev_token.span); + + if !args.options_spans.is_empty() { let mut err = p .sess .span_diagnostic - .struct_span_err(new_span, "clobber_abi is not allowed after options"); + .struct_span_err(full_span, "clobber_abi is not allowed after options"); err.span_labels(args.options_spans.clone(), "options"); return Err(err); } - args.clobber_abi = Some((clobber_abi, new_span)); + match &new_abis[..] { + // should have errored above during parsing + [] => unreachable!(), + [(abi, _span)] => args.clobber_abis.push((*abi, full_span)), + [abis @ ..] => { + for (abi, span) in abis { + args.clobber_abis.push((*abi, *span)); + } + } + } Ok(()) } @@ -770,7 +800,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option( ident: Ident::invalid(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(inline_asm), + kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), vis: ast::Visibility { span: sp.shrink_to_lo(), kind: ast::VisibilityKind::Inherited, diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index eb0fdebb665fa..a16388d5de219 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -35,7 +35,8 @@ where ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { - let unused_params = self.tcx.unused_generic_params(def_id); + let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let unused_params = self.tcx.unused_generic_params(instance); for (index, subst) in substs.into_iter().enumerate() { let index = index .try_into() diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 38c099fa4f59c..1b123520961a6 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -171,7 +171,7 @@ fn get_features( } if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() { - if allowed.iter().find(|&f| name.as_str() == *f).is_none() { + if allowed.iter().all(|f| name.as_str() != *f) { struct_span_err!( span_handler, mi.span(), diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4e7f85d2c3727..e12f049a90bdf 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -83,6 +83,12 @@ impl IntoArgs for (CrateNum, DefId) { } } +impl IntoArgs for ty::InstanceDef<'tcx> { + fn into_args(self) -> (DefId, DefId) { + (self.def_id(), self.def_id()) + } +} + provide! { <'tcx> tcx, def_id, other, cdata, type_of => { cdata.get_type(def_id.index, tcx) } generics_of => { cdata.get_generics(def_id.index, tcx.sess) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index dacb1e4029c20..20f7b059b5600 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1319,7 +1319,9 @@ impl EncodeContext<'a, 'tcx> { } record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); - let unused = self.tcx.unused_generic_params(def_id); + let instance = + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); + let unused = self.tcx.unused_generic_params(instance); if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b6358f9929448..a36c9b6ed7304 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -1004,13 +1004,13 @@ impl Allocation { /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes` /// error which will report the first range of bytes which is uninitialized. fn check_init(&self, range: AllocRange) -> AllocResult { - self.is_init(range).or_else(|idx_range| { - Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess { + self.is_init(range).map_err(|idx_range| { + AllocError::InvalidUninitBytes(Some(UninitBytesAccess { access_offset: range.start, access_size: range.size, uninit_offset: idx_range.start, uninit_size: idx_range.end - idx_range.start, // `Size` subtraction - }))) + })) }) } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 67a20d72905f9..06b42320049f0 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -47,6 +47,14 @@ pub enum MonoItem<'tcx> { } impl<'tcx> MonoItem<'tcx> { + /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). + pub fn is_user_defined(&self) -> bool { + match *self { + MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)), + MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true, + } + } + pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { match *self { MonoItem::Fn(instance) => { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e3eda8483b692..4145cbd42495c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1558,11 +1558,11 @@ rustc_queries! { query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } - query unused_generic_params(key: DefId) -> FiniteBitSet { - cache_on_disk_if { key.is_local() } + query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet { + cache_on_disk_if { key.def_id().is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", - tcx.def_path_str(key) + tcx.def_path_str(key.def_id()) } } query backend_optimization_level(_: ()) -> OptLevel { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 9b8247fd0283e..4b38105e44717 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -152,6 +152,22 @@ impl<'tcx> InstanceDef<'tcx> { } } + /// Returns the `DefId` of instances which might not require codegen locally. + pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { + match self { + ty::InstanceDef::Item(def) => Some(def.did), + ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), + InstanceDef::VtableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => None, + } + } + #[inline] pub fn with_opt_param(self) -> ty::WithOptConstParam { match self { @@ -567,29 +583,26 @@ impl<'tcx> Instance<'tcx> { return self; } - if let InstanceDef::Item(def) = self.def { - let polymorphized_substs = polymorphize(tcx, def.did, self.substs); - debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); - Self { def: self.def, substs: polymorphized_substs } - } else { - self - } + let polymorphized_substs = polymorphize(tcx, self.def, self.substs); + debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); + Self { def: self.def, substs: polymorphized_substs } } } fn polymorphize<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + instance: ty::InstanceDef<'tcx>, substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { - debug!("polymorphize({:?}, {:?})", def_id, substs); - let unused = tcx.unused_generic_params(def_id); + debug!("polymorphize({:?}, {:?})", instance, substs); + let unused = tcx.unused_generic_params(instance); debug!("polymorphize: unused={:?}", unused); // If this is a closure or generator then we need to handle the case where another closure // from the function is captured as an upvar and hasn't been polymorphized. In this case, // the unpolymorphized upvar closure would result in a polymorphized closure producing // multiple mono items (and eventually symbol clashes). + let def_id = instance.def_id(); let upvars_ty = if tcx.is_closure(def_id) { Some(substs.as_closure().tupled_upvars_ty()) } else if tcx.type_of(def_id).is_generator() { @@ -613,7 +626,11 @@ fn polymorphize<'tcx>( debug!("fold_ty: ty={:?}", ty); match ty.kind { ty::Closure(def_id, substs) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { @@ -621,7 +638,11 @@ fn polymorphize<'tcx>( } } ty::Generator(def_id, substs, movability) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f06426308a228..5147408210ef5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -450,7 +450,9 @@ fn collect_items_rec<'tcx>( // involving a dependency, and the lack of context is confusing) in this MVP, we focus on // diagnostics on edges crossing a crate boundary: the collected mono items which are not // defined in the local crate. - if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE + if tcx.sess.diagnostic().err_count() > error_count + && starting_point.node.krate() != LOCAL_CRATE + && starting_point.node.is_user_defined() { let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string()); tcx.sess.span_note_without_error( @@ -934,21 +936,13 @@ fn visit_instance_use<'tcx>( } } -// Returns `true` if we should codegen an instance in the local crate. -// Returns `false` if we can just link to the upstream crate and therefore don't -// need a mono item. +/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we +/// can just link to the upstream crate and therefore don't need a mono item. fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { - let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, - ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id, - ty::InstanceDef::VtableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Intrinsic(_) - | ty::InstanceDef::CloneShim(..) => return true, + let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() { + def_id + } else { + return true; }; if tcx.is_foreign_item(def_id) { diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 429ed53d37977..be6820822586d 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -9,7 +9,7 @@ use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::ty::print::characteristic_def_id_of_type; -use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt}; +use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt}; use rustc_span::symbol::Symbol; use super::PartitioningCx; @@ -300,14 +300,21 @@ fn characteristic_def_id_of_mono_item<'tcx>( // call it. return None; } - // This is a method within an impl, find out what the self-type is: - let impl_self_ty = tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - tcx.type_of(impl_def_id), - ); - if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { - return Some(def_id); + + // When polymorphization is enabled, methods which do not depend on their generic + // parameters, but the self-type of their impl block do will fail to normalize. + if !tcx.sess.opts.debugging_opts.polymorphize + || !instance.definitely_needs_subst(tcx) + { + // This is a method within an impl, find out what the self-type is: + let impl_self_ty = tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + tcx.type_of(impl_def_id), + ); + if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { + return Some(def_id); + } } } diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 0f768b7819b5b..e6e4438b6d41a 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -27,20 +27,23 @@ pub fn provide(providers: &mut Providers) { providers.unused_generic_params = unused_generic_params; } -/// Determine which generic parameters are used by the function/method/closure represented by -/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty` -/// indicates all parameters are used). +/// Determine which generic parameters are used by the instance. +/// +/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all +/// parameters are used). #[instrument(level = "debug", skip(tcx))] -fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { +fn unused_generic_params<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, +) -> FiniteBitSet { if !tcx.sess.opts.debugging_opts.polymorphize { // If polymorphization disabled, then all parameters are used. return FiniteBitSet::new_empty(); } - // Polymorphization results are stored in cross-crate metadata only when there are unused - // parameters, so assume that non-local items must have only used parameters (else this query - // would not be invoked, and the cross-crate metadata used instead). - if !def_id.is_local() { + let def_id = instance.def_id(); + // Exit early if this instance should not be polymorphized. + if !should_polymorphize(tcx, def_id, instance) { return FiniteBitSet::new_empty(); } @@ -52,41 +55,25 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { return FiniteBitSet::new_empty(); } - // Exit early when there is no MIR available. - let context = tcx.hir().body_const_context(def_id.expect_local()); - match context { - Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => { - debug!("no mir available"); - return FiniteBitSet::new_empty(); - } - Some(_) if !tcx.is_ctfe_mir_available(def_id) => { - debug!("no ctfe mir available"); - return FiniteBitSet::new_empty(); - } - _ => {} - } - // Create a bitset with N rightmost ones for each parameter. let generics_count: u32 = generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); let mut unused_parameters = FiniteBitSet::::new_empty(); unused_parameters.set_range(0..generics_count); debug!(?unused_parameters, "(start)"); + mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); debug!(?unused_parameters, "(after default)"); // Visit MIR and accumululate used generic parameters. - let body = match context { + let body = match tcx.hir().body_const_context(def_id.expect_local()) { // Const functions are actually called and should thus be considered for polymorphization - // via their runtime MIR + // via their runtime MIR. Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id), Some(_) => tcx.mir_for_ctfe(def_id), }; let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters }; vis.visit_body(body); - debug!(?unused_parameters, "(after visitor)"); - - mark_used_by_predicates(tcx, def_id, &mut unused_parameters); debug!(?unused_parameters, "(end)"); // Emit errors for debugging and testing if enabled. @@ -97,6 +84,49 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { unused_parameters } +/// Returns `true` if the instance should be polymorphized. +fn should_polymorphize<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + instance: ty::InstanceDef<'tcx>, +) -> bool { + // If an instance's MIR body is not polymorphic then the modified substitutions that are + // derived from polymorphization's result won't make any difference. + if !instance.has_polymorphic_mir_body() { + return false; + } + + // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic. + if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) { + return false; + } + + // Polymorphization results are stored in cross-crate metadata only when there are unused + // parameters, so assume that non-local items must have only used parameters (else this query + // would not be invoked, and the cross-crate metadata used instead). + if !def_id.is_local() { + return false; + } + + // Foreign items have no bodies to analyze. + if tcx.is_foreign_item(def_id) { + return false; + } + + // Make sure there is MIR available. + match tcx.hir().body_const_context(def_id.expect_local()) { + Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => { + debug!("no mir available"); + return false; + } + Some(_) if !tcx.is_ctfe_mir_available(def_id) => { + debug!("no ctfe mir available"); + return false; + } + _ => true, + } +} + /// Some parameters are considered used-by-default, such as non-generic parameters and the dummy /// generic parameters from closures, this function marks them as used. `leaf_is_closure` should /// be `true` if the item that `unused_generic_params` was invoked on is a closure. @@ -156,44 +186,6 @@ fn mark_used_by_default_parameters<'tcx>( } } -/// Search the predicates on used generic parameters for any unused generic parameters, and mark -/// those as used. -#[instrument(level = "debug", skip(tcx, def_id))] -fn mark_used_by_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - unused_parameters: &mut FiniteBitSet, -) { - let def_id = tcx.closure_base_def_id(def_id); - let predicates = tcx.explicit_predicates_of(def_id); - - let mut current_unused_parameters = FiniteBitSet::new_empty(); - // Run to a fixed point to support `where T: Trait, U: Trait`, starting with an empty - // bit set so that this is skipped if all parameters are already used. - while current_unused_parameters != *unused_parameters { - debug!(?current_unused_parameters, ?unused_parameters); - current_unused_parameters = *unused_parameters; - - for (predicate, _) in predicates.predicates { - // Consider all generic params in a predicate as used if any other parameter in the - // predicate is used. - let any_param_used = { - let mut vis = HasUsedGenericParams { tcx, unused_parameters }; - predicate.visit_with(&mut vis).is_break() - }; - - if any_param_used { - let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters }; - predicate.visit_with(&mut vis); - } - } - } - - if let Some(parent) = predicates.parent { - mark_used_by_predicates(tcx, parent, unused_parameters); - } -} - /// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic /// parameter which was unused. #[instrument(level = "debug", skip(tcx, generics))] @@ -243,7 +235,8 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { /// a closure, generator or constant). #[instrument(level = "debug", skip(self, def_id, substs))] fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { - let unused = self.tcx.unused_generic_params(def_id); + let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let unused = self.tcx.unused_generic_params(instance); debug!(?self.unused_parameters, ?unused); for (i, arg) in substs.iter().enumerate() { let i = i.try_into().unwrap(); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e3970038a33b0..05675e086d777 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1837,7 +1837,7 @@ crate fn show_candidates( .skip(1) .all(|(_, descr, _)| descr == descr_first) { - format!("{}", descr_first) + descr_first.to_string() } else { "item".to_string() }; diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 5ac9fdec0cf58..7456f886ea5d8 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -323,6 +323,7 @@ pub struct AssertParamIsEq { /// ``` #[derive(Clone, Copy, PartialEq, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(i8)] pub enum Ordering { /// An ordering where a compared value is less than another. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 401267f5613ee..885058321589c 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -646,7 +646,8 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_mut(&mut self) -> Option<&mut T> { + #[rustc_const_unstable(feature = "const_option", issue = "67441")] + pub const fn as_mut(&mut self) -> Option<&mut T> { match *self { Some(ref mut x) => Some(x), None => None, diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 3608853dce4e0..cf669163d3ef2 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -10,6 +10,7 @@ #![feature(const_assume)] #![feature(const_cell_into_inner)] #![feature(const_maybe_uninit_assume_init)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_ptr_offset)] diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index 8995f96b1238a..c9508c145258c 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -380,6 +380,14 @@ const fn option_const_mut() { let _take = option.take(); let _replace = option.replace(42); + + { + let as_mut = option.as_mut(); + match as_mut { + Some(v) => *v = 32, + None => unreachable!(), + } + } } #[test] diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 7dc09add27fd7..824283ef6c41e 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -303,6 +303,7 @@ mod inner { pub fn actually_monotonic() -> bool { (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) + || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64")) || cfg!(target_os = "fuchsia") } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 5efd8c9be5633..3e27e3a429771 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -268,6 +268,20 @@ impl Instant { // // To hopefully mitigate the impact of this, a few platforms are // excluded as "these at least haven't gone backwards yet". + // + // While issues have been seen on arm64 platforms the Arm architecture + // requires that the counter monotonically increases and that it must + // provide a uniform view of system time (e.g. it must not be possible + // for a core to recieve a message from another core with a time stamp + // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While + // there have been a few 64bit SoCs that have bugs which cause time to + // not monoticially increase, these have been fixed in the Linux kernel + // and we shouldn't penalize all Arm SoCs for those who refuse to + // update their kernels: + // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1 + // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10 + // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11 + // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12 if time::Instant::actually_monotonic() { return Instant(os_now); } diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 5a2cef24870be..dcf3e65a71667 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -319,7 +319,7 @@ fn call_foo(arg: i32) -> i32 { Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`: the compiler will automatically insert the appropriate mangled symbol name into the assembly code. -By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. +By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. Multiple `clobber_abi` arguments may be provided and all clobbers from all specified ABIs will be inserted. ## Register template modifiers @@ -453,10 +453,10 @@ reg_spec := / "" operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" reg_operand := dir_spec "(" reg_spec ")" operand_expr operand := reg_operand / "const" const_expr / "sym" path -clobber_abi := "clobber_abi(" ")" +clobber_abi := "clobber_abi(" *["," ] [","] ")" option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" options := "options(" option *["," option] [","] ")" -asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] *("," options) [","] ")" +asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")" ``` Inline assembly is currently supported on the following architectures: @@ -799,6 +799,8 @@ As stated in the previous section, passing an input value smaller than the regis The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm` block. This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list. +`clobber_abi` may be specified any number of times. It will insert a clobber for all unique registers in the union of all specified calling conventions. + Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register. Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output. The following ABIs can be used with `clobber_abi`: diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9f2e282fce1c3..c46439b851050 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -765,7 +765,7 @@ crate fn find_testable_code( // If there are characters between the preceding line ending and // this code block, `str::lines` will return an additional line, // which we subtract here. - if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with("\n") { + if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with('\n') { nb_lines -= 1; } let line = tests.get_line() + nb_lines + 1; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 36b1a14f6c1ea..b13ab64011dc1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -113,11 +113,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .unwrap_or(&[]) .iter() .filter_map(|attr| { - Some( - Cfg::parse(attr.meta_item()?) - .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) - .ok()?, - ) + Cfg::parse(attr.meta_item()?) + .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) + .ok() }) .collect::>() }) diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs index 3ad56aebc21c5..e58bba6405853 100644 --- a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs +++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs @@ -11,7 +11,6 @@ impl Struct { pub const AssocConst: Self::AssocTy = 42; //~^ ERROR ambiguous associated type //~| HELP use fully-qualified syntax - // FIXME: for some reason, the error is shown twice with rustdoc but only once with rustc //~| ERROR ambiguous associated type //~| HELP use fully-qualified syntax } diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs index faa5e37b781ec..48016f2a6cf54 100644 --- a/src/test/ui/asm/aarch64/parse-error.rs +++ b/src/test/ui/asm/aarch64/parse-error.rs @@ -51,7 +51,6 @@ fn main() { asm!("{}", options(), clobber_abi("C"), const foo); //~^ ERROR clobber_abi is not allowed after options asm!("", clobber_abi("C"), clobber_abi("C")); - //~^ ERROR clobber_abi specified multiple times asm!("{a}", a = const foo, a = const bar); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used @@ -121,7 +120,7 @@ global_asm!("", options(), clobber_abi("C")); global_asm!("{}", options(), clobber_abi("C"), const FOO); //~^ ERROR clobber_abi is not allowed after options global_asm!("", clobber_abi("C"), clobber_abi("C")); -//~^ ERROR clobber_abi specified multiple times +//~^ ERROR `clobber_abi` cannot be used with `global_asm!` global_asm!("{a}", a = const FOO, a = const BAR); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr index 7b9fa90f70c25..b3e3a6ff7ebfe 100644 --- a/src/test/ui/asm/aarch64/parse-error.stderr +++ b/src/test/ui/asm/aarch64/parse-error.stderr @@ -132,16 +132,8 @@ LL | asm!("{}", options(), clobber_abi("C"), const foo); | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:53:36 - | -LL | asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here - error: duplicate argument named `a` - --> $DIR/parse-error.rs:55:36 + --> $DIR/parse-error.rs:54:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -149,7 +141,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | previously here error: argument never used - --> $DIR/parse-error.rs:55:36 + --> $DIR/parse-error.rs:54:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used @@ -157,13 +149,13 @@ LL | asm!("{a}", a = const foo, a = const bar); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:60:18 + --> $DIR/parse-error.rs:59:18 | LL | asm!("", a = in("x0") foo); | ^^^^^^^^^^^^^^^^ error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:62:35 + --> $DIR/parse-error.rs:61:35 | LL | asm!("{a}", in("x0") foo, a = const bar); | ------------ ^^^^^^^^^^^^^ named argument @@ -171,7 +163,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | explicit register argument error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:65:35 + --> $DIR/parse-error.rs:64:35 | LL | asm!("{a}", in("x0") foo, a = const bar); | ------------ ^^^^^^^^^^^^^ named argument @@ -179,7 +171,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | explicit register argument error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:68:35 + --> $DIR/parse-error.rs:67:35 | LL | asm!("{1}", in("x0") foo, const bar); | ------------ ^^^^^^^^^ positional argument @@ -187,19 +179,19 @@ LL | asm!("{1}", in("x0") foo, const bar); | explicit register argument error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` - --> $DIR/parse-error.rs:71:29 + --> $DIR/parse-error.rs:70:29 | LL | asm!("", options(), ""); | ^^ expected one of 9 possible tokens error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:73:33 + --> $DIR/parse-error.rs:72:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); | ^^^^ expected one of 9 possible tokens error: asm template must be a string literal - --> $DIR/parse-error.rs:75:14 + --> $DIR/parse-error.rs:74:14 | LL | asm!(format!("{{{}}}", 0), in(reg) foo); | ^^^^^^^^^^^^^^^^^^^^ @@ -207,7 +199,7 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:77:21 + --> $DIR/parse-error.rs:76:21 | LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); | ^^^^^^^^^^^^^^^^^^^^ @@ -215,79 +207,79 @@ LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: _ cannot be used for input operands - --> $DIR/parse-error.rs:79:28 + --> $DIR/parse-error.rs:78:28 | LL | asm!("{}", in(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:81:31 + --> $DIR/parse-error.rs:80:31 | LL | asm!("{}", inout(reg) _); | ^ error: _ cannot be used for input operands - --> $DIR/parse-error.rs:83:35 + --> $DIR/parse-error.rs:82:35 | LL | asm!("{}", inlateout(reg) _); | ^ error: requires at least a template string argument - --> $DIR/parse-error.rs:90:1 + --> $DIR/parse-error.rs:89:1 | LL | global_asm!(); | ^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/parse-error.rs:92:13 + --> $DIR/parse-error.rs:91:13 | LL | global_asm!(FOO); | ^^^ error: expected token: `,` - --> $DIR/parse-error.rs:94:18 + --> $DIR/parse-error.rs:93:18 | LL | global_asm!("{}" FOO); | ^^^ expected `,` error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:96:19 + --> $DIR/parse-error.rs:95:19 | LL | global_asm!("{}", FOO); | ^^^ expected operand, options, or additional template string error: expected expression, found end of macro arguments - --> $DIR/parse-error.rs:98:24 + --> $DIR/parse-error.rs:97:24 | LL | global_asm!("{}", const); | ^ expected expression error: expected one of `,`, `.`, `?`, or an operator, found `FOO` - --> $DIR/parse-error.rs:100:30 + --> $DIR/parse-error.rs:99:30 | LL | global_asm!("{}", const(reg) FOO); | ^^^ expected one of `,`, `.`, `?`, or an operator error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` - --> $DIR/parse-error.rs:102:25 + --> $DIR/parse-error.rs:101:25 | LL | global_asm!("", options(FOO)); | ^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:104:25 + --> $DIR/parse-error.rs:103:25 | LL | global_asm!("", options(nomem FOO)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/parse-error.rs:106:25 + --> $DIR/parse-error.rs:105:25 | LL | global_asm!("", options(nomem, FOO)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: arguments are not allowed after options - --> $DIR/parse-error.rs:108:30 + --> $DIR/parse-error.rs:107:30 | LL | global_asm!("{}", options(), const FOO); | --------- ^^^^^^^^^ argument @@ -295,25 +287,25 @@ LL | global_asm!("{}", options(), const FOO); | previous options error: expected string literal - --> $DIR/parse-error.rs:110:29 + --> $DIR/parse-error.rs:109:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal error: expected `)`, found `FOO` - --> $DIR/parse-error.rs:112:33 + --> $DIR/parse-error.rs:111:33 | LL | global_asm!("", clobber_abi("C" FOO)); | ^^^ expected `)` error: expected `)`, found `,` - --> $DIR/parse-error.rs:114:32 + --> $DIR/parse-error.rs:113:32 | LL | global_asm!("", clobber_abi("C", FOO)); | ^ expected `)` error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:116:37 + --> $DIR/parse-error.rs:115:37 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ---------------- ^^^^^^^^^ argument @@ -321,13 +313,13 @@ LL | global_asm!("{}", clobber_abi("C"), const FOO); | clobber_abi error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:116:19 + --> $DIR/parse-error.rs:115:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:119:28 + --> $DIR/parse-error.rs:118:28 | LL | global_asm!("", options(), clobber_abi("C")); | --------- ^^^^^^^^^^^^^^^^ @@ -335,23 +327,21 @@ LL | global_asm!("", options(), clobber_abi("C")); | options error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:121:30 + --> $DIR/parse-error.rs:120:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | --------- ^^^^^^^^^^^^^^^^ | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:123:35 +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:122:35 | LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here + | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` - --> $DIR/parse-error.rs:125:35 + --> $DIR/parse-error.rs:124:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -359,7 +349,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:125:35 + --> $DIR/parse-error.rs:124:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -367,19 +357,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: expected one of `clobber_abi`, `const`, or `options`, found `""` - --> $DIR/parse-error.rs:128:28 + --> $DIR/parse-error.rs:127:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, or `options` error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` - --> $DIR/parse-error.rs:130:30 + --> $DIR/parse-error.rs:129:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, or `options` error: asm template must be a string literal - --> $DIR/parse-error.rs:132:13 + --> $DIR/parse-error.rs:131:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -387,7 +377,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:134:20 + --> $DIR/parse-error.rs:133:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -413,7 +403,7 @@ LL | asm!("{}", clobber_abi("C"), const foo); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:55:31 + --> $DIR/parse-error.rs:54:31 | LL | let mut foo = 0; | ---------- help: consider using `const` instead of `let`: `const foo` @@ -422,7 +412,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:55:46 + --> $DIR/parse-error.rs:54:46 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -431,7 +421,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:62:45 + --> $DIR/parse-error.rs:61:45 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -440,7 +430,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:65:45 + --> $DIR/parse-error.rs:64:45 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -449,7 +439,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:68:41 + --> $DIR/parse-error.rs:67:41 | LL | let mut bar = 0; | ---------- help: consider using `const` instead of `let`: `const bar` @@ -457,6 +447,6 @@ LL | let mut bar = 0; LL | asm!("{1}", in("x0") foo, const bar); | ^^^ non-constant value -error: aborting due to 66 previous errors +error: aborting due to 65 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.rs b/src/test/ui/asm/x86_64/bad-clobber-abi.rs new file mode 100644 index 0000000000000..f4ca033048d71 --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-clobber-abi.rs @@ -0,0 +1,32 @@ +// needs-asm-support +// only-x86_64 + +// checks various modes of failure for the `clobber_abi` argument (after parsing) + +#![feature(asm)] + +fn main() { + unsafe { + asm!("", clobber_abi("C")); + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("", clobber_abi("C", "foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("", clobber_abi("C", "C")); + //~^ ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64", "sysv64")); + asm!("", clobber_abi("win64", "efiapi")); + //~^ ERROR `win64` ABI specified multiple times + asm!("", clobber_abi("C", "foo", "C")); + //~^ ERROR invalid ABI for `clobber_abi` + //~| ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64", "foo", "efiapi")); + //~^ ERROR invalid ABI for `clobber_abi` + //~| ERROR `win64` ABI specified multiple times + asm!("", clobber_abi("C"), clobber_abi("C")); + //~^ ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64"), clobber_abi("sysv64")); + asm!("", clobber_abi("win64"), clobber_abi("efiapi")); + //~^ ERROR `win64` ABI specified multiple times + } +} diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.stderr b/src/test/ui/asm/x86_64/bad-clobber-abi.stderr new file mode 100644 index 0000000000000..46e91a3951fb5 --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-clobber-abi.stderr @@ -0,0 +1,88 @@ +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:11:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:13:35 + | +LL | asm!("", clobber_abi("C", "foo")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:15:35 + | +LL | asm!("", clobber_abi("C", "C")); + | --- ^^^ + | | + | previously specified here + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:18:39 + | +LL | asm!("", clobber_abi("win64", "efiapi")); + | ------- ^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:20:35 + | +LL | asm!("", clobber_abi("C", "foo", "C")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:20:42 + | +LL | asm!("", clobber_abi("C", "foo", "C")); + | --- ^^^ + | | + | previously specified here + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:23:39 + | +LL | asm!("", clobber_abi("win64", "foo", "efiapi")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:23:46 + | +LL | asm!("", clobber_abi("win64", "foo", "efiapi")); + | ------- ^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:26:36 + | +LL | asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | previously specified here + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:29:40 + | +LL | asm!("", clobber_abi("win64"), clobber_abi("efiapi")); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/x86_64/bad-options.rs b/src/test/ui/asm/x86_64/bad-options.rs index dc61d1612e8d6..3facc87641569 100644 --- a/src/test/ui/asm/x86_64/bad-options.rs +++ b/src/test/ui/asm/x86_64/bad-options.rs @@ -21,6 +21,9 @@ fn main() { //~^ ERROR invalid ABI for `clobber_abi` asm!("{}", out(reg) foo, clobber_abi("C")); //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + //~| ERROR `C` ABI specified multiple times asm!("", out("eax") foo, clobber_abi("C")); } } diff --git a/src/test/ui/asm/x86_64/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr index 8cfd450ab02a5..e2351840eef21 100644 --- a/src/test/ui/asm/x86_64/bad-options.stderr +++ b/src/test/ui/asm/x86_64/bad-options.stderr @@ -36,38 +36,47 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C")); | | | generic outputs +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:24:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- ---------------- clobber_abi + | | | + | | clobber_abi + | generic outputs + error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` - --> $DIR/bad-options.rs:28:25 + --> $DIR/bad-options.rs:31:25 | LL | global_asm!("", options(nomem)); | ^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` - --> $DIR/bad-options.rs:30:25 + --> $DIR/bad-options.rs:33:25 | LL | global_asm!("", options(readonly)); | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` - --> $DIR/bad-options.rs:32:25 + --> $DIR/bad-options.rs:35:25 | LL | global_asm!("", options(noreturn)); | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `pure` - --> $DIR/bad-options.rs:34:25 + --> $DIR/bad-options.rs:37:25 | LL | global_asm!("", options(pure)); | ^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` - --> $DIR/bad-options.rs:36:25 + --> $DIR/bad-options.rs:39:25 | LL | global_asm!("", options(nostack)); | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` - --> $DIR/bad-options.rs:38:25 + --> $DIR/bad-options.rs:41:25 | LL | global_asm!("", options(preserves_flags)); | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` @@ -80,5 +89,13 @@ LL | asm!("", clobber_abi("foo")); | = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` -error: aborting due to 13 previous errors +error: `C` ABI specified multiple times + --> $DIR/bad-options.rs:24:52 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | previously specified here + +error: aborting due to 15 previous errors diff --git a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs new file mode 100644 index 0000000000000..10aa004d431bd --- /dev/null +++ b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs @@ -0,0 +1,33 @@ +// run-pass +// needs-asm-support +// only-x86_64 + +// Checks that multiple clobber_abi options can be used + +#![feature(asm)] + +extern "sysv64" fn foo(x: i32) -> i32 { + x + 16 +} + +extern "win64" fn bar(x: i32) -> i32 { + x / 2 +} + +fn main() { + let x = 8; + let y: i32; + // call `foo` with `x` as the input, and then `bar` with the output of `foo` + // and output that to `y` + unsafe { + asm!( + "call {}; mov rcx, rax; call {}", + sym foo, + sym bar, + in("rdi") x, + out("rax") y, + clobber_abi("sysv64", "win64"), + ); + } + assert_eq!((x, y), (8, 12)); +} diff --git a/src/test/ui/asm/x86_64/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs index fa14c52cf0ad7..fdf3e40c7d375 100644 --- a/src/test/ui/asm/x86_64/parse-error.rs +++ b/src/test/ui/asm/x86_64/parse-error.rs @@ -37,12 +37,14 @@ fn main() { asm!("{}", options(), const foo); //~^ ERROR arguments are not allowed after options //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", clobber_abi()); + //~^ ERROR at least one abi must be provided asm!("", clobber_abi(foo)); //~^ ERROR expected string literal asm!("", clobber_abi("C" foo)); - //~^ ERROR expected `)`, found `foo` + //~^ ERROR expected one of `)` or `,`, found `foo` asm!("", clobber_abi("C", foo)); - //~^ ERROR expected `)`, found `,` + //~^ ERROR expected string literal asm!("{}", clobber_abi("C"), const foo); //~^ ERROR arguments are not allowed after clobber_abi //~^^ ERROR attempt to use a non-constant value in a constant @@ -50,8 +52,6 @@ fn main() { //~^ ERROR clobber_abi is not allowed after options asm!("{}", options(), clobber_abi("C"), const foo); //~^ ERROR clobber_abi is not allowed after options - asm!("", clobber_abi("C"), clobber_abi("C")); - //~^ ERROR clobber_abi specified multiple times asm!("{a}", a = const foo, a = const bar); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used @@ -110,9 +110,9 @@ global_asm!("{}", options(), const FOO); global_asm!("", clobber_abi(FOO)); //~^ ERROR expected string literal global_asm!("", clobber_abi("C" FOO)); -//~^ ERROR expected `)`, found `FOO` +//~^ ERROR expected one of `)` or `,`, found `FOO` global_asm!("", clobber_abi("C", FOO)); -//~^ ERROR expected `)`, found `,` +//~^ ERROR expected string literal global_asm!("{}", clobber_abi("C"), const FOO); //~^ ERROR arguments are not allowed after clobber_abi //~^^ ERROR `clobber_abi` cannot be used with `global_asm!` @@ -121,7 +121,7 @@ global_asm!("", options(), clobber_abi("C")); global_asm!("{}", options(), clobber_abi("C"), const FOO); //~^ ERROR clobber_abi is not allowed after options global_asm!("", clobber_abi("C"), clobber_abi("C")); -//~^ ERROR clobber_abi specified multiple times +//~^ ERROR `clobber_abi` cannot be used with `global_asm!` global_asm!("{a}", a = const FOO, a = const BAR); //~^ ERROR duplicate argument named `a` //~^^ ERROR argument never used diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr index 78d342cc1daf7..ea12d5487257a 100644 --- a/src/test/ui/asm/x86_64/parse-error.stderr +++ b/src/test/ui/asm/x86_64/parse-error.stderr @@ -90,26 +90,32 @@ LL | asm!("{}", options(), const foo); | | | previous options -error: expected string literal +error: at least one abi must be provided as an argument to `clobber_abi` --> $DIR/parse-error.rs:40:30 | +LL | asm!("", clobber_abi()); + | ^ + +error: expected string literal + --> $DIR/parse-error.rs:42:30 + | LL | asm!("", clobber_abi(foo)); | ^^^ not a string literal -error: expected `)`, found `foo` - --> $DIR/parse-error.rs:42:34 +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:44:34 | LL | asm!("", clobber_abi("C" foo)); - | ^^^ expected `)` + | ^^^ expected one of `)` or `,` -error: expected `)`, found `,` - --> $DIR/parse-error.rs:44:33 +error: expected string literal + --> $DIR/parse-error.rs:46:35 | LL | asm!("", clobber_abi("C", foo)); - | ^ expected `)` + | ^^^ not a string literal error: arguments are not allowed after clobber_abi - --> $DIR/parse-error.rs:46:38 + --> $DIR/parse-error.rs:48:38 | LL | asm!("{}", clobber_abi("C"), const foo); | ---------------- ^^^^^^^^^ argument @@ -117,7 +123,7 @@ LL | asm!("{}", clobber_abi("C"), const foo); | clobber_abi error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:49:29 + --> $DIR/parse-error.rs:51:29 | LL | asm!("", options(), clobber_abi("C")); | --------- ^^^^^^^^^^^^^^^^ @@ -125,21 +131,13 @@ LL | asm!("", options(), clobber_abi("C")); | options error: clobber_abi is not allowed after options - --> $DIR/parse-error.rs:51:31 + --> $DIR/parse-error.rs:53:31 | LL | asm!("{}", options(), clobber_abi("C"), const foo); | --------- ^^^^^^^^^^^^^^^^ | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:53:36 - | -LL | asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here - error: duplicate argument named `a` --> $DIR/parse-error.rs:55:36 | @@ -300,17 +298,17 @@ error: expected string literal LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal -error: expected `)`, found `FOO` +error: expected one of `)` or `,`, found `FOO` --> $DIR/parse-error.rs:112:33 | LL | global_asm!("", clobber_abi("C" FOO)); - | ^^^ expected `)` + | ^^^ expected one of `)` or `,` -error: expected `)`, found `,` - --> $DIR/parse-error.rs:114:32 +error: expected string literal + --> $DIR/parse-error.rs:114:34 | LL | global_asm!("", clobber_abi("C", FOO)); - | ^ expected `)` + | ^^^ not a string literal error: arguments are not allowed after clobber_abi --> $DIR/parse-error.rs:116:37 @@ -342,13 +340,11 @@ LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | | | options -error: clobber_abi specified multiple times - --> $DIR/parse-error.rs:123:35 +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:123:17 | LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); - | ---------------- ^^^^^^^^^^^^^^^^ - | | - | clobber_abi previously specified here + | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` --> $DIR/parse-error.rs:125:35 @@ -404,7 +400,7 @@ LL | asm!("{}", options(), const foo); | ^^^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/parse-error.rs:46:44 + --> $DIR/parse-error.rs:48:44 | LL | let mut foo = 0; | ---------- help: consider using `const` instead of `let`: `const foo` diff --git a/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs index 97f1ef2c90ae0..dea1e21e77fe3 100644 --- a/src/test/ui/polymorphization/predicates.rs +++ b/src/test/ui/polymorphization/predicates.rs @@ -12,6 +12,7 @@ fn bar() { #[rustc_polymorphize_error] fn foo(_: I) +//~^ ERROR item has unused generic parameters where I: Iterator, { @@ -20,6 +21,7 @@ where #[rustc_polymorphize_error] fn baz(_: I) +//~^ ERROR item has unused generic parameters where std::iter::Repeat: Iterator, { @@ -40,6 +42,7 @@ where #[rustc_polymorphize_error] fn next(&mut self) -> Option { self.find(|_| true) + //~^ ERROR item has unused generic parameters } } @@ -53,6 +56,7 @@ impl Baz for u16 {} #[rustc_polymorphize_error] fn quux() -> usize +//~^ ERROR item has unused generic parameters where A: Baz, B: Baz, @@ -69,6 +73,7 @@ impl Foobar for () {} #[rustc_polymorphize_error] fn foobar() -> usize +//~^ ERROR item has unused generic parameters where (): Foobar, { diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr index c23730fc995e7..5fc51e58d728a 100644 --- a/src/test/ui/polymorphization/predicates.stderr +++ b/src/test/ui/polymorphization/predicates.stderr @@ -1,8 +1,45 @@ +error: item has unused generic parameters + --> $DIR/predicates.rs:14:4 + | +LL | fn foo(_: I) + | ^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/predicates.rs:23:4 + | +LL | fn baz(_: I) + | ^^^ - generic parameter `T` is unused + +error: item has unused generic parameters + --> $DIR/predicates.rs:44:19 + | +LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E> + | - - generic parameter `E` is unused + | | + | generic parameter `I` is unused +... +LL | self.find(|_| true) + | ^^^^^^^^ + +error: item has unused generic parameters + --> $DIR/predicates.rs:58:4 + | +LL | fn quux() -> usize + | ^^^^ - - generic parameter `B` is unused + | | + | generic parameter `A` is unused + +error: item has unused generic parameters + --> $DIR/predicates.rs:75:4 + | +LL | fn foobar() -> usize + | ^^^^^^ - generic parameter `F` is unused + error: item has unused generic parameters --> $DIR/predicates.rs:9:4 | LL | fn bar() { | ^^^ - generic parameter `I` is unused -error: aborting due to previous error +error: aborting due to 6 previous errors