diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9227b81f12fac..ae3a1a4138716 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -259,6 +259,9 @@ pub enum AttributeKind { /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), + /// Represents `#[rustc_skip_during_method_dispatch]`. + SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span }, + /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. Stability { stability: Stability, diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 24c40c301fe08..0fa69c401546f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -50,8 +50,8 @@ impl SingleAttributeParser for ColdParser { const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return None; } @@ -67,8 +67,8 @@ pub(crate) struct NakedParser { impl AttributeParser for NakedParser { const ATTRIBUTES: AcceptMapping = &[(&[sym::naked], template!(Word), |this, cx, args| { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return; } @@ -175,10 +175,10 @@ impl SingleAttributeParser for NoMangleParser { const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + if let Err(span) = args.no_args() { + cx.expected_no_args(span); return None; - }; + } Some(AttributeKind::NoMangle(cx.attr_span)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 4cfd9a82ce8d2..1c8fc5079dad3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -14,8 +14,10 @@ impl SingleAttributeParser for AsPtrParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { - // FIXME: check that there's no args (this is currently checked elsewhere) + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::AsPtr(cx.attr_span)) } } @@ -27,8 +29,10 @@ impl SingleAttributeParser for PubTransparentParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { - // FIXME: check that there's no args (this is currently checked elsewhere) + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::PubTransparent(cx.attr_span)) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 738d8735b6924..ac7e90fd90256 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -36,6 +36,7 @@ pub(crate) mod must_use; pub(crate) mod repr; pub(crate) mod semantics; pub(crate) mod stability; +pub(crate) mod traits; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 071574a5612aa..54f50445fbdff 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -13,7 +13,10 @@ impl SingleAttributeParser for MayDangleParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::MayDangle(cx.attr_span)) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6871ff4ec9f39..37104855623f4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -139,7 +139,10 @@ impl SingleAttributeParser for ConstStabilityIndirectParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; const TEMPLATE: AttributeTemplate = template!(Word); - fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + } Some(AttributeKind::ConstStabilityIndirect) } } @@ -361,8 +364,8 @@ pub(crate) fn parse_unstability( }; } Some(sym::soft) => { - if !param.args().no_args() { - cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() }); + if let Err(span) = args.no_args() { + cx.emit_err(session_diagnostics::SoftNoArgs { span }); } is_soft = true; } diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs new file mode 100644 index 0000000000000..83a98c53c7f74 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -0,0 +1,54 @@ +use core::mem; + +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct SkipDuringMethodDispatchParser; + +impl SingleAttributeParser for SkipDuringMethodDispatchParser { + const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + + const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let mut array = false; + let mut boxed_slice = false; + let Some(args) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + if args.is_empty() { + cx.expected_at_least_one_argument(args.span); + return None; + } + for arg in args.mixed() { + let Some(arg) = arg.meta_item() else { + cx.unexpected_literal(arg.span()); + continue; + }; + if let Err(span) = arg.args().no_args() { + cx.expected_no_args(span); + } + let path = arg.path(); + let (key, skip): (Symbol, &mut bool) = match path.word_sym() { + Some(key @ sym::array) => (key, &mut array), + Some(key @ sym::boxed_slice) => (key, &mut boxed_slice), + _ => { + cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]); + continue; + } + }; + if mem::replace(skip, true) { + cx.duplicate_key(arg.span(), key); + } + } + Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 457e073c488b0..43b2d07dbe100 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -26,6 +26,7 @@ use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; +use crate::attributes::traits::SkipDuringMethodDispatchParser; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; @@ -119,6 +120,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, // tidy-alphabetical-end ]; @@ -325,6 +327,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument, + }) + } + pub(crate) fn expected_specific_argument( &self, span: Span, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index e02dc098127cf..aecaae947c99b 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -169,9 +169,15 @@ impl<'a> ArgParser<'a> { } } - /// Asserts that there are no arguments - pub fn no_args(&self) -> bool { - matches!(self, Self::NoArgs) + /// Assert that there were no args. + /// If there were, get a span to the arguments + /// (to pass to [`AcceptContext::expected_no_args`](crate::context::AcceptContext::expected_no_args)). + pub fn no_args(&self) -> Result<(), Span> { + match self { + Self::NoArgs => Ok(()), + Self::List(args) => Err(args.span), + Self::NameValue(args) => Err(args.eq_span.to(args.value_span)), + } } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 808e452799d3c..263b323e3eb1f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -496,6 +496,7 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub(crate) enum AttributeParseErrorReason { ExpectedNoArgs, ExpectedStringLiteral { byte_string: Option }, + ExpectedAtLeastOneArgument, ExpectedSingleArgument, ExpectedList, UnexpectedLiteral, @@ -539,6 +540,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.span_label(self.span, "expected a single argument here"); diag.code(E0805); } + AttributeParseErrorReason::ExpectedAtLeastOneArgument => { + diag.span_label(self.span, "expected at least 1 argument here"); + } AttributeParseErrorReason::ExpectedList => { diag.span_label(self.span, "expected this to be a list"); } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8fc83908efbcc..6a4dd80c81730 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -337,7 +337,12 @@ pub(crate) trait Linker { fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); + fn export_symbols( + &mut self, + tmpdir: &Path, + crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ); fn subsystem(&mut self, subsystem: &str); fn linker_plugin_lto(&mut self); fn add_eh_frame_header(&mut self) {} @@ -770,7 +775,12 @@ impl<'a> Linker for GccLinker<'a> { } } - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -799,7 +809,7 @@ impl<'a> Linker for GccLinker<'a> { // Write a plain, newline-separated list of symbols let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; - for sym in symbols { + for (sym, _) in symbols { debug!(" _{sym}"); writeln!(f, "_{sym}")?; } @@ -814,11 +824,12 @@ impl<'a> Linker for GccLinker<'a> { // .def file similar to MSVC one but without LIBRARY section // because LD doesn't like when it's empty writeln!(f, "EXPORTS")?; - for symbol in symbols { + for (symbol, kind) in symbols { + let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; debug!(" _{symbol}"); // Quote the name in case it's reserved by linker in some way // (this accounts for names with dots in particular). - writeln!(f, " \"{symbol}\"")?; + writeln!(f, " \"{symbol}\"{kind_marker}")?; } }; if let Err(error) = res { @@ -831,7 +842,7 @@ impl<'a> Linker for GccLinker<'a> { writeln!(f, "{{")?; if !symbols.is_empty() { writeln!(f, " global:")?; - for sym in symbols { + for (sym, _) in symbols { debug!(" {sym};"); writeln!(f, " {sym};")?; } @@ -1098,7 +1109,12 @@ impl<'a> Linker for MsvcLinker<'a> { // crates. Upstream rlibs may be linked statically to this dynamic library, // in which case they may continue to transitively be used and hence need // their symbols exported. - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { // Symbol visibility takes care of this typically if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -1116,9 +1132,10 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - for symbol in symbols { + for (symbol, kind) in symbols { + let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; + writeln!(f, " {symbol}{kind_marker}")?; } }; if let Err(error) = res { @@ -1259,14 +1276,19 @@ impl<'a> Linker for EmLinker<'a> { self.cc_arg("-nodefaultlibs"); } - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { debug!("EXPORTED SYMBOLS:"); self.cc_arg("-s"); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( - &symbols.iter().map(|sym| "_".to_owned() + sym).collect::>(), + &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::>(), ) .unwrap(); debug!("{encoded}"); @@ -1428,8 +1450,13 @@ impl<'a> Linker for WasmLd<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { - for sym in symbols { + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { + for (sym, _) in symbols { self.link_args(&["--export", sym]); } @@ -1563,7 +1590,7 @@ impl<'a> Linker for L4Bender<'a> { self.cc_arg("-nostdlib"); } - fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { + fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) { // ToDo, not implemented, copy from GCC self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented); } @@ -1720,12 +1747,17 @@ impl<'a> Linker for AixLinker<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { let path = tmpdir.join("list.exp"); let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; // FIXME: use llvm-nm to generate export list. - for symbol in symbols { + for (symbol, _) in symbols { debug!(" _{symbol}"); writeln!(f, " {symbol}")?; } @@ -1769,9 +1801,23 @@ fn for_each_exported_symbols_include_dep<'tcx>( } } -pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { +pub(crate) fn exported_symbols( + tcx: TyCtxt<'_>, + crate_type: CrateType, +) -> Vec<(String, SymbolExportKind)> { if let Some(ref exports) = tcx.sess.target.override_export_symbols { - return exports.iter().map(ToString::to_string).collect(); + return exports + .iter() + .map(|name| { + ( + name.to_string(), + // FIXME use the correct export kind for this symbol. override_export_symbols + // can't directly specify the SymbolExportKind as it is defined in rustc_middle + // which rustc_target can't depend on. + SymbolExportKind::Text, + ) + }) + .collect(); } if let CrateType::ProcMacro = crate_type { @@ -1781,7 +1827,10 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec, crate_type: CrateType) -> Vec { +fn exported_symbols_for_non_proc_macro( + tcx: TyCtxt<'_>, + crate_type: CrateType, +) -> Vec<(String, SymbolExportKind)> { let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { @@ -1789,8 +1838,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) - // from any cdylib. The latter doesn't work anyway as we use hidden visibility for // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning. if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) { - symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( - tcx, symbol, cnum, + symbols.push(( + symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum), + info.kind, )); symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum); } @@ -1799,7 +1849,7 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) - symbols } -fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec { +fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> { // `exported_symbols` will be empty when !should_codegen. if !tcx.sess.opts.output_types.should_codegen() { return Vec::new(); @@ -1809,7 +1859,10 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec { let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx); - vec![proc_macro_decls_name, metadata_symbol_name] + vec![ + (proc_macro_decls_name, SymbolExportKind::Data), + (metadata_symbol_name, SymbolExportKind::Data), + ] } pub(crate) fn linked_symbols( @@ -1817,8 +1870,13 @@ pub(crate) fn linked_symbols( crate_type: CrateType, ) -> Vec<(String, SymbolExportKind)> { match crate_type { - CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (), - CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { + CrateType::Executable + | CrateType::ProcMacro + | CrateType::Cdylib + | CrateType::Dylib + | CrateType::Sdylib => (), + CrateType::Staticlib | CrateType::Rlib => { + // These are not linked, so no need to generate symbols.o for them. return Vec::new(); } } @@ -1831,7 +1889,9 @@ pub(crate) fn linked_symbols( || info.used { symbols.push(( - symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), + symbol_export::linking_symbol_name_for_instance_in_crate( + tcx, symbol, info.kind, cnum, + ), info.kind, )); } @@ -1906,7 +1966,13 @@ impl<'a> Linker for PtxLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + _symbols: &[(String, SymbolExportKind)], + ) { + } fn subsystem(&mut self, _subsystem: &str) {} @@ -1975,10 +2041,15 @@ impl<'a> Linker for LlbcLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + _tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { match _crate_type { CrateType::Cdylib => { - for sym in symbols { + for (sym, _) in symbols { self.link_args(&["--export-symbol", sym]); } } @@ -2052,11 +2123,16 @@ impl<'a> Linker for BpfLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + fn export_symbols( + &mut self, + tmpdir: &Path, + _crate_type: CrateType, + symbols: &[(String, SymbolExportKind)], + ) { let path = tmpdir.join("symbols"); let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; - for sym in symbols { + for (sym, _) in symbols { writeln!(f, "{sym}")?; } }; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index d0b6c7470fb9a..19c005d418e89 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -680,6 +680,7 @@ fn calling_convention_for_symbol<'tcx>( pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, + export_kind: SymbolExportKind, instantiating_crate: CrateNum, ) -> String { let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); @@ -700,8 +701,9 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( let prefix = match &target.arch[..] { "x86" => Some('_'), "x86_64" => None, - "arm64ec" => Some('#'), - // Only x86/64 use symbol decorations. + // Only functions are decorated for arm64ec. + "arm64ec" if export_kind == SymbolExportKind::Text => Some('#'), + // Only x86/64 and arm64ec use symbol decorations. _ => return undecorated, }; @@ -741,7 +743,7 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>( /// Add it to the symbols list for all kernel functions, so that it is exported in the linked /// object. pub(crate) fn extend_exported_symbols<'tcx>( - symbols: &mut Vec, + symbols: &mut Vec<(String, SymbolExportKind)>, tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, instantiating_crate: CrateNum, @@ -755,7 +757,9 @@ pub(crate) fn extend_exported_symbols<'tcx>( let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); // Add the symbol for the kernel descriptor (with .kd suffix) - symbols.push(format!("{undecorated}.kd")); + // Per https://llvm.org/docs/AMDGPUUsage.html#symbols these will always be `STT_OBJECT` so + // export as data. + symbols.push((format!("{undecorated}.kd"), SymbolExportKind::Data)); } fn maybe_emutls_symbol_name<'tcx>( diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a3d6c73ba8560..cc90271cd0c6f 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -12,9 +12,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_data_structures::unord::UnordMap; -use rustc_hir::ItemId; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; +use rustc_hir::{ItemId, Target}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; @@ -1003,21 +1003,35 @@ impl CrateInfo { // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { - let missing_weak_lang_items: FxIndexSet = info + let add_prefix = match (target.is_like_windows, target.arch.as_ref()) { + (true, "x86") => |name: String, _: SymbolExportKind| format!("_{name}"), + (true, "arm64ec") => { + // Only functions are decorated for arm64ec. + |name: String, export_kind: SymbolExportKind| match export_kind { + SymbolExportKind::Text => format!("#{name}"), + _ => name, + } + } + _ => |name: String, _: SymbolExportKind| name, + }; + let missing_weak_lang_items: FxIndexSet<(Symbol, SymbolExportKind)> = info .used_crates .iter() .flat_map(|&cnum| tcx.missing_lang_items(cnum)) .filter(|l| l.is_weak()) .filter_map(|&l| { let name = l.link_name()?; - lang_items::required(tcx, l).then_some(name) + let export_kind = match l.target() { + Target::Fn => SymbolExportKind::Text, + Target::Static => SymbolExportKind::Data, + _ => bug!( + "Don't know what the export kind is for lang item of kind {:?}", + l.target() + ), + }; + lang_items::required(tcx, l).then_some((name, export_kind)) }) .collect(); - let prefix = match (target.is_like_windows, target.arch.as_ref()) { - (true, "x86") => "_", - (true, "arm64ec") => "#", - _ => "", - }; // This loop only adds new items to values of the hash map, so the order in which we // iterate over the values is not important. @@ -1030,10 +1044,13 @@ impl CrateInfo { .for_each(|(_, linked_symbols)| { let mut symbols = missing_weak_lang_items .iter() - .map(|item| { + .map(|(item, export_kind)| { ( - format!("{prefix}{}", mangle_internal_symbol(tcx, item.as_str())), - SymbolExportKind::Text, + add_prefix( + mangle_internal_symbol(tcx, item.as_str()), + *export_kind, + ), + *export_kind, ) }) .collect::>(); @@ -1048,12 +1065,12 @@ impl CrateInfo { // errors. linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| { ( - format!( - "{prefix}{}", + add_prefix( mangle_internal_symbol( tcx, - global_fn_name(method.name).as_str() - ) + global_fn_name(method.name).as_str(), + ), + SymbolExportKind::Text, ), SymbolExportKind::Text, ) diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 523c9f2ad1cea..23ed387a3ff97 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -218,7 +218,7 @@ pub struct CrateInfo { pub target_cpu: String, pub target_features: Vec, pub crate_types: Vec, - pub exported_symbols: UnordMap>, + pub exported_symbols: UnordMap>, pub linked_symbols: FxIndexMap>, pub local_crate_name: Symbol, pub compiler_builtins: Option, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 280b33f072343..3540c9b4bf0bd 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1083,7 +1083,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[rustc_main]` attribute is used internally to specify test entry point function", ), rustc_attr!( - rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing, + rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), ErrorFollowing, EncodeCrossCrate::No, "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \ from method dispatch when the receiver is of the following type, for compatibility in \ diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 176d955bf032d..c967e87bfd87c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -21,6 +21,7 @@ use std::ops::Bound; use rustc_abi::ExternAbi; use rustc_ast::Recovered; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ @@ -1151,22 +1152,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive); let is_fundamental = tcx.has_attr(def_id, sym::fundamental); - // FIXME: We could probably do way better attribute validation here. - let mut skip_array_during_method_dispatch = false; - let mut skip_boxed_slice_during_method_dispatch = false; - for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) { - if let Some(lst) = attr.meta_item_list() { - for item in lst { - if let Some(ident) = item.ident() { - match ident.as_str() { - "array" => skip_array_during_method_dispatch = true, - "boxed_slice" => skip_boxed_slice_during_method_dispatch = true, - _ => (), - } - } - } - } - } + let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!( + tcx.get_all_attrs(def_id), + AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice] + ) + .unwrap_or([false; 2]); let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) { ty::trait_def::TraitSpecializationKind::Marker diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 1d67d0fe3bbf4..64a1f2aff15c5 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -22,7 +22,7 @@ impl SymbolExportLevel { } /// Kind of exported symbols. -#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)] +#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable, Hash)] pub enum SymbolExportKind { Text, Data, diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 8e6442353c3e9..47e29923ee59f 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -286,13 +286,20 @@ fn emit_malformed_attribute( if matches!( name, sym::inline + | sym::may_dangle + | sym::rustc_as_ptr + | sym::rustc_pub_transparent + | sym::rustc_const_stable_indirect | sym::rustc_force_inline | sym::rustc_confusables + | sym::rustc_skip_during_method_dispatch | sym::repr | sym::align | sym::deprecated | sym::optimize | sym::cold + | sym::naked + | sym::no_mangle | sym::must_use ) { return; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c2a58b4cd7d53..25b8417944351 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -118,6 +118,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs { let mut style = None; match attr { + Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch { + span: attr_span, + .. + }) => { + self.check_must_be_applied_to_trait(*attr_span, span, target); + } Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { self.check_confusables(*first_span, target); } @@ -250,7 +256,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_must_implement_one_of, ..] | [sym::rustc_deny_explicit_impl, ..] | [sym::rustc_do_not_implement_via_object, ..] - | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), + | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), @@ -1805,14 +1811,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if the attribute is applied to a trait. - fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) { + fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) { match target { Target::Trait => {} _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span(), - defn_span: span, - }); + self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span }); } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 684b1781b44ef..5861ae4a372b7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -577,6 +577,7 @@ symbols! { box_new, box_patterns, box_syntax, + boxed_slice, bpf_target_feature, braced_empty_structs, branch, diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs index f9638fea225b7..55fdacb014e67 100644 --- a/library/core/src/marker/variance.rs +++ b/library/core/src/marker/variance.rs @@ -18,7 +18,7 @@ macro_rules! phantom_type { pub struct $name:ident <$t:ident> ($($inner:tt)*); )*) => {$( $(#[$attr])* - pub struct $name<$t>($($inner)*) where T: ?Sized; + pub struct $name<$t>($($inner)*) where $t: ?Sized; impl $name where T: ?Sized diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 0e3c3aaee0ff7..99044e2a25300 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -683,6 +683,7 @@ impl Builder<'_> { .arg("--print=file-names") .arg("--crate-type=proc-macro") .arg("-") + .stdin(std::process::Stdio::null()) .run_capture(self) .stderr(); diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index eb9802bf2e1ba..78b28ac182823 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -119,6 +119,11 @@ impl<'a> BootstrapCommand { self } + pub fn stdin(&mut self, stdin: std::process::Stdio) -> &mut Self { + self.command.stdin(stdin); + self + } + #[must_use] pub fn delay_failure(self) -> Self { Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0778b5b56f5d6..f51b35097f66a 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -194,22 +194,25 @@ impl FromClean for Deprecation { } impl FromClean for Option> { - fn from_clean(args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArgs::*; - if args.is_empty() { - return None; - } - Some(Box::new(match args { - AngleBracketed { args, constraints } => GenericArgs::AngleBracketed { - args: args.into_json(renderer), - constraints: constraints.into_json(renderer), - }, - Parenthesized { inputs, output } => GenericArgs::Parenthesized { + match generic_args { + AngleBracketed { args, constraints } => { + if generic_args.is_empty() { + None + } else { + Some(Box::new(GenericArgs::AngleBracketed { + args: args.into_json(renderer), + constraints: constraints.into_json(renderer), + })) + } + } + Parenthesized { inputs, output } => Some(Box::new(GenericArgs::Parenthesized { inputs: inputs.into_json(renderer), output: output.into_json(renderer), - }, - ReturnTypeNotation => GenericArgs::ReturnTypeNotation, - })) + })), + ReturnTypeNotation => Some(Box::new(GenericArgs::ReturnTypeNotation)), + } } } diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index b5a2b7feac9d6..9fa26305f6b0b 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -16,6 +16,8 @@ pub enum ErrorKind { Suggestion, Warning, Raw, + /// Used for better recovery and diagnostics in compiletest. + Unknown, } impl ErrorKind { @@ -31,21 +33,25 @@ impl ErrorKind { /// Either the canonical uppercase string, or some additional versions for compatibility. /// FIXME: consider keeping only the canonical versions here. - pub fn from_user_str(s: &str) -> ErrorKind { - match s { + fn from_user_str(s: &str) -> Option { + Some(match s { "HELP" | "help" => ErrorKind::Help, "ERROR" | "error" => ErrorKind::Error, - // `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct, - // but those tests never use the error kind later on. - "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note, + "NOTE" | "note" => ErrorKind::Note, "SUGGESTION" => ErrorKind::Suggestion, "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, "RAW" => ErrorKind::Raw, - _ => panic!( + _ => return None, + }) + } + + pub fn expect_from_user_str(s: &str) -> ErrorKind { + ErrorKind::from_user_str(s).unwrap_or_else(|| { + panic!( "unexpected diagnostic kind `{s}`, expected \ - `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`" - ), - } + `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` or `RAW`" + ) + }) } } @@ -58,6 +64,7 @@ impl fmt::Display for ErrorKind { ErrorKind::Suggestion => write!(f, "SUGGESTION"), ErrorKind::Warning => write!(f, "WARN"), ErrorKind::Raw => write!(f, "RAW"), + ErrorKind::Unknown => write!(f, "UNKNOWN"), } } } @@ -65,6 +72,7 @@ impl fmt::Display for ErrorKind { #[derive(Debug)] pub struct Error { pub line_num: Option, + pub column_num: Option, /// What kind of message we expect (e.g., warning, error, suggestion). pub kind: ErrorKind, pub msg: String, @@ -74,17 +82,6 @@ pub struct Error { pub require_annotation: bool, } -impl Error { - pub fn render_for_expected(&self) -> String { - use colored::Colorize; - format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan()) - } - - pub fn line_num_str(&self) -> String { - self.line_num.map_or("?".to_string(), |line_num| line_num.to_string()) - } -} - /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE" /// The former is a "follow" that inherits its target from the preceding line; /// the latter is an "adjusts" that goes that many lines up. @@ -168,8 +165,10 @@ fn parse_expected( let rest = line[tag.end()..].trim_start(); let (kind_str, _) = rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, "")); - let kind = ErrorKind::from_user_str(kind_str); - let untrimmed_msg = &rest[kind_str.len()..]; + let (kind, untrimmed_msg) = match ErrorKind::from_user_str(kind_str) { + Some(kind) => (kind, &rest[kind_str.len()..]), + None => (ErrorKind::Unknown, rest), + }; let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned(); let line_num_adjust = &captures["adjust"]; @@ -182,6 +181,7 @@ fn parse_expected( } else { (false, Some(line_num - line_num_adjust.len())) }; + let column_num = Some(tag.start() + 1); debug!( "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}", @@ -191,7 +191,7 @@ fn parse_expected( kind, msg ); - Some((follow_prev, Error { line_num, kind, msg, require_annotation: true })) + Some((follow_prev, Error { line_num, column_num, kind, msg, require_annotation: true })) } #[cfg(test)] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 8bee9caacc949..2b203bb309c63 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -593,7 +593,7 @@ impl TestProps { config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) { self.dont_require_annotations - .insert(ErrorKind::from_user_str(err_kind.trim())); + .insert(ErrorKind::expect_from_user_str(err_kind.trim())); } }, ); diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 6ed2b52c66d21..a8e6416e56c84 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -36,9 +36,7 @@ struct UnusedExternNotification { struct DiagnosticSpan { file_name: String, line_start: usize, - line_end: usize, column_start: usize, - column_end: usize, is_primary: bool, label: Option, suggested_replacement: Option, @@ -148,6 +146,7 @@ pub fn parse_output(file_name: &str, output: &str) -> Vec { Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), Err(_) => errors.push(Error { line_num: None, + column_num: None, kind: ErrorKind::Raw, msg: line.to_string(), require_annotation: false, @@ -193,25 +192,9 @@ fn push_actual_errors( // also ensure that `//~ ERROR E123` *always* works. The // assumption is that these multi-line error messages are on their // way out anyhow. - let with_code = |span: Option<&DiagnosticSpan>, text: &str| { - // FIXME(#33000) -- it'd be better to use a dedicated - // UI harness than to include the line/col number like - // this, but some current tests rely on it. - // - // Note: Do NOT include the filename. These can easily - // cause false matches where the expected message - // appears in the filename, and hence the message - // changes but the test still passes. - let span_str = match span { - Some(DiagnosticSpan { line_start, column_start, line_end, column_end, .. }) => { - format!("{line_start}:{column_start}: {line_end}:{column_end}") - } - None => format!("?:?: ?:?"), - }; - match &diagnostic.code { - Some(code) => format!("{span_str}: {text} [{}]", code.code), - None => format!("{span_str}: {text}"), - } + let with_code = |text| match &diagnostic.code { + Some(code) => format!("{text} [{}]", code.code), + None => format!("{text}"), }; // Convert multi-line messages into multiple errors. @@ -225,8 +208,9 @@ fn push_actual_errors( || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap(); errors.push(Error { line_num: None, + column_num: None, kind, - msg: with_code(None, first_line), + msg: with_code(first_line), require_annotation: diagnostic.level != "failure-note" && !RE.get_or_init(re_init).is_match(first_line), }); @@ -234,8 +218,9 @@ fn push_actual_errors( for span in primary_spans { errors.push(Error { line_num: Some(span.line_start), + column_num: Some(span.column_start), kind, - msg: with_code(Some(span), first_line), + msg: with_code(first_line), require_annotation: true, }); } @@ -244,16 +229,18 @@ fn push_actual_errors( if primary_spans.is_empty() { errors.push(Error { line_num: None, + column_num: None, kind, - msg: with_code(None, next_line), + msg: with_code(next_line), require_annotation: false, }); } else { for span in primary_spans { errors.push(Error { line_num: Some(span.line_start), + column_num: Some(span.column_start), kind, - msg: with_code(Some(span), next_line), + msg: with_code(next_line), require_annotation: false, }); } @@ -266,6 +253,7 @@ fn push_actual_errors( for (index, line) in suggested_replacement.lines().enumerate() { errors.push(Error { line_num: Some(span.line_start + index), + column_num: Some(span.column_start), kind: ErrorKind::Suggestion, msg: line.to_string(), // Empty suggestions (suggestions to remove something) are common @@ -288,6 +276,7 @@ fn push_actual_errors( if let Some(label) = &span.label { errors.push(Error { line_num: Some(span.line_start), + column_num: Some(span.column_start), kind: ErrorKind::Note, msg: label.clone(), // Empty labels (only underlining spans) are common and do not need annotations. @@ -310,6 +299,7 @@ fn push_backtrace( if Path::new(&expansion.span.file_name) == Path::new(&file_name) { errors.push(Error { line_num: Some(expansion.span.line_start), + column_num: Some(expansion.span.column_start), kind: ErrorKind::Note, msg: format!("in this expansion of {}", expansion.macro_decl_name), require_annotation: true, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 42c851ea99910..980e89889abba 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -11,7 +11,7 @@ use std::{env, iter, str}; use build_helper::fs::remove_and_create_dir_all; use camino::{Utf8Path, Utf8PathBuf}; -use colored::Colorize; +use colored::{Color, Colorize}; use regex::{Captures, Regex}; use tracing::*; @@ -677,9 +677,6 @@ impl<'test> TestCx<'test> { return; } - // On Windows, translate all '\' path separators to '/' - let file_name = self.testpaths.file.to_string().replace(r"\", "/"); - // On Windows, keep all '\' path separators to match the paths reported in the JSON output // from the compiler let diagnostic_file_name = if self.props.remap_src_base { @@ -704,6 +701,7 @@ impl<'test> TestCx<'test> { .map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e }); let mut unexpected = Vec::new(); + let mut unimportant = Vec::new(); let mut found = vec![false; expected_errors.len()]; for actual_error in actual_errors { for pattern in &self.props.error_patterns { @@ -738,14 +736,9 @@ impl<'test> TestCx<'test> { && expected_kinds.contains(&actual_error.kind) && !self.props.dont_require_annotations.contains(&actual_error.kind) { - self.error(&format!( - "{}:{}: unexpected {}: '{}'", - file_name, - actual_error.line_num_str(), - actual_error.kind, - actual_error.msg - )); unexpected.push(actual_error); + } else { + unimportant.push(actual_error); } } } @@ -755,39 +748,140 @@ impl<'test> TestCx<'test> { // anything not yet found is a problem for (index, expected_error) in expected_errors.iter().enumerate() { if !found[index] { - self.error(&format!( - "{}:{}: expected {} not found: {}", - file_name, - expected_error.line_num_str(), - expected_error.kind, - expected_error.msg - )); not_found.push(expected_error); } } if !unexpected.is_empty() || !not_found.is_empty() { self.error(&format!( - "{} unexpected errors found, {} expected errors not found", + "{} unexpected diagnostics reported, {} expected diagnostics not reported", unexpected.len(), not_found.len() )); - println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); + + // Emit locations in a format that is short (relative paths) but "clickable" in editors. + // Also normalize path separators to `/`. + let file_name = self + .testpaths + .file + .strip_prefix(self.config.src_root.as_str()) + .unwrap_or(&self.testpaths.file) + .to_string() + .replace(r"\", "/"); + let line_str = |e: &Error| { + let line_num = e.line_num.map_or("?".to_string(), |line_num| line_num.to_string()); + // `file:?:NUM` may be confusing to editors and unclickable. + let opt_col_num = match e.column_num { + Some(col_num) if line_num != "?" => format!(":{col_num}"), + _ => "".to_string(), + }; + format!("{file_name}:{line_num}{opt_col_num}") + }; + let print_error = |e| println!("{}: {}: {}", line_str(e), e.kind, e.msg.cyan()); + let push_suggestion = + |suggestions: &mut Vec<_>, e: &Error, kind, line, msg, color, rank| { + let mut ret = String::new(); + if kind { + ret += &format!("{} {}", "with kind".color(color), e.kind); + } + if line { + if !ret.is_empty() { + ret.push(' '); + } + ret += &format!("{} {}", "on line".color(color), line_str(e)); + } + if msg { + if !ret.is_empty() { + ret.push(' '); + } + ret += &format!("{} {}", "with message".color(color), e.msg.cyan()); + } + suggestions.push((ret, rank)); + }; + let show_suggestions = |mut suggestions: Vec<_>, prefix: &str, color| { + // Only show suggestions with the highest rank. + suggestions.sort_by_key(|(_, rank)| *rank); + if let Some(&(_, top_rank)) = suggestions.first() { + for (suggestion, rank) in suggestions { + if rank == top_rank { + println!(" {} {suggestion}", prefix.color(color)); + } + } + } + }; + + // Fuzzy matching quality: + // - message and line / message and kind - great, suggested + // - only message - good, suggested + // - known line and kind - ok, suggested + // - only known line - meh, but suggested + // - others are not worth suggesting if !unexpected.is_empty() { - println!("{}", "--- unexpected errors (from JSON output) ---".green()); + let header = "--- reported in JSON output but not expected in test file ---"; + println!("{}", header.green()); for error in &unexpected { - println!("{}", error.render_for_expected()); + print_error(error); + let mut suggestions = Vec::new(); + for candidate in ¬_found { + let mut push_red_suggestion = |line, msg, rank| { + push_suggestion( + &mut suggestions, + candidate, + candidate.kind != error.kind, + line, + msg, + Color::Red, + rank, + ) + }; + if error.msg.contains(&candidate.msg) { + push_red_suggestion(candidate.line_num != error.line_num, false, 0); + } else if candidate.line_num.is_some() + && candidate.line_num == error.line_num + { + push_red_suggestion(false, true, 1); + } + } + + show_suggestions(suggestions, "expected", Color::Red); } println!("{}", "---".green()); } if !not_found.is_empty() { - println!("{}", "--- not found errors (from test file) ---".red()); + let header = "--- expected in test file but not reported in JSON output ---"; + println!("{}", header.red()); for error in ¬_found { - println!("{}", error.render_for_expected()); + print_error(error); + let mut suggestions = Vec::new(); + for candidate in unexpected.iter().chain(&unimportant) { + let mut push_green_suggestion = |line, msg, rank| { + push_suggestion( + &mut suggestions, + candidate, + candidate.kind != error.kind, + line, + msg, + Color::Green, + rank, + ) + }; + if candidate.msg.contains(&error.msg) { + push_green_suggestion(candidate.line_num != error.line_num, false, 0); + } else if candidate.line_num.is_some() + && candidate.line_num == error.line_num + { + push_green_suggestion(false, true, 1); + } + } + + show_suggestions(suggestions, "reported", Color::Green); } - println!("{}", "---\n".red()); + println!("{}", "---".red()); } - panic!("errors differ from expected"); + panic!( + "errors differ from expected\nstatus: {}\ncommand: {}\n", + proc_res.status, proc_res.cmdline + ); } } @@ -2073,7 +2167,6 @@ impl<'test> TestCx<'test> { println!("{}", String::from_utf8_lossy(&output.stdout)); eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } else { - use colored::Colorize; eprintln!("warning: no pager configured, falling back to unified diff"); eprintln!( "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`" diff --git a/tests/incremental/issue-61323.rs b/tests/incremental/issue-61323.rs index b7423c81fc163..4845648d49c87 100644 --- a/tests/incremental/issue-61323.rs +++ b/tests/incremental/issue-61323.rs @@ -1,7 +1,7 @@ //@ revisions: rpass cfail enum A { - //[cfail]~^ ERROR 3:1: 3:7: recursive types `A` and `C` have infinite size [E0072] + //[cfail]~^ ERROR recursive types `A` and `C` have infinite size [E0072] B(C), } diff --git a/tests/run-make/arm64ec-import-export-static/export.rs b/tests/run-make/arm64ec-import-export-static/export.rs new file mode 100644 index 0000000000000..ca6ccf00ca17e --- /dev/null +++ b/tests/run-make/arm64ec-import-export-static/export.rs @@ -0,0 +1,27 @@ +#![crate_type = "dylib"] +#![allow(internal_features)] +#![feature(no_core, lang_items)] +#![no_core] +#![no_std] + +// This is needed because of #![no_core]: +#[lang = "pointee_sized"] +pub trait PointeeSized {} +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} +#[lang = "sized"] +pub trait Sized: MetaSized {} +#[lang = "sync"] +trait Sync {} +impl Sync for i32 {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for i32 {} +#[lang = "drop_in_place"] +pub unsafe fn drop_in_place(_: *mut T) {} +#[no_mangle] +extern "system" fn _DllMainCRTStartup(_: *const u8, _: u32, _: *const u8) -> u32 { + 1 +} + +pub static VALUE: i32 = 42; diff --git a/tests/run-make/arm64ec-import-export-static/import.rs b/tests/run-make/arm64ec-import-export-static/import.rs new file mode 100644 index 0000000000000..9d52db251250a --- /dev/null +++ b/tests/run-make/arm64ec-import-export-static/import.rs @@ -0,0 +1,12 @@ +#![crate_type = "cdylib"] +#![allow(internal_features)] +#![feature(no_core)] +#![no_std] +#![no_core] + +extern crate export; + +#[no_mangle] +pub extern "C" fn func() -> i32 { + export::VALUE +} diff --git a/tests/run-make/arm64ec-import-export-static/rmake.rs b/tests/run-make/arm64ec-import-export-static/rmake.rs new file mode 100644 index 0000000000000..7fa31144810df --- /dev/null +++ b/tests/run-make/arm64ec-import-export-static/rmake.rs @@ -0,0 +1,15 @@ +// Test that a static can be exported from one crate and imported into another. +// +// This was broken for Arm64EC as only functions, not variables, should be +// decorated with `#`. +// See https://github.com/rust-lang/rust/issues/138541 + +//@ needs-llvm-components: aarch64 +//@ only-windows + +use run_make_support::rustc; + +fn main() { + rustc().input("export.rs").target("aarch64-pc-windows-msvc").panic("abort").run(); + rustc().input("import.rs").target("aarch64-pc-windows-msvc").panic("abort").run(); +} diff --git a/tests/run-make/sanitizer-dylib-link/program.rs b/tests/run-make/sanitizer-dylib-link/program.rs index 1026c7f89ba9f..dbf885d343fea 100644 --- a/tests/run-make/sanitizer-dylib-link/program.rs +++ b/tests/run-make/sanitizer-dylib-link/program.rs @@ -1,4 +1,4 @@ -#[cfg_attr(windows, link(name = "library.dll.lib", modifiers = "+verbatim"))] +#[cfg_attr(windows, link(name = "library", kind = "raw-dylib"))] #[cfg_attr(not(windows), link(name = "library"))] extern "C" { fn overflow(); diff --git a/tests/run-make/used-proc-macro/dep.rs b/tests/run-make/used-proc-macro/dep.rs new file mode 100644 index 0000000000000..9f881d926d61d --- /dev/null +++ b/tests/run-make/used-proc-macro/dep.rs @@ -0,0 +1,4 @@ +#![crate_type = "lib"] + +#[used] +static VERY_IMPORTANT_SYMBOL: u32 = 12345; diff --git a/tests/run-make/used-proc-macro/proc_macro.rs b/tests/run-make/used-proc-macro/proc_macro.rs new file mode 100644 index 0000000000000..af592ea0c7e5b --- /dev/null +++ b/tests/run-make/used-proc-macro/proc_macro.rs @@ -0,0 +1,3 @@ +#![crate_type = "proc-macro"] + +extern crate dep as _; diff --git a/tests/run-make/used-proc-macro/rmake.rs b/tests/run-make/used-proc-macro/rmake.rs new file mode 100644 index 0000000000000..8e6dd3f3e4abb --- /dev/null +++ b/tests/run-make/used-proc-macro/rmake.rs @@ -0,0 +1,17 @@ +// Test that #[used] statics are included in the final dylib for proc-macros too. + +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro +//@ ignore-musl (FIXME: can't find `-lunwind`) + +use run_make_support::{dynamic_lib_name, llvm_readobj, rustc}; + +fn main() { + rustc().input("dep.rs").run(); + rustc().input("proc_macro.rs").run(); + llvm_readobj() + .input(dynamic_lib_name("proc_macro")) + .arg("--all") + .run() + .assert_stdout_contains("VERY_IMPORTANT_SYMBOL"); +} diff --git a/tests/rustdoc-json/generic-args.rs b/tests/rustdoc-json/generic-args.rs index 0f588820da75d..b4a73a046b506 100644 --- a/tests/rustdoc-json/generic-args.rs +++ b/tests/rustdoc-json/generic-args.rs @@ -17,4 +17,7 @@ pub fn my_fn1(_: ::MyType) {} //@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" null pub fn my_fn2(_: IntoIterator) {} +//@ is "$.index[?(@.name=='my_fn3')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.args.parenthesized.inputs" [] +pub fn my_fn3(f: impl FnMut()) {} + fn main() {} diff --git a/tests/ui/argument-suggestions/issue-100478.rs b/tests/ui/argument-suggestions/issue-100478.rs index b0a9703112e31..219870f3b2373 100644 --- a/tests/ui/argument-suggestions/issue-100478.rs +++ b/tests/ui/argument-suggestions/issue-100478.rs @@ -32,8 +32,8 @@ fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} fn main() { three_diff(T2::new(0)); //~ ERROR function takes - four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR 35:5: 35:17: arguments to this function are incorrect [E0308] - four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR 36:5: 36:17: arguments to this function are incorrect [E0308] + four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR arguments to this function are incorrect [E0308] + four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR arguments to this function are incorrect [E0308] let p1 = T1::new(0); let p2 = Arc::new(T2::new(0)); diff --git a/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed b/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed index c74a32e442f3f..9e5e889506c78 100644 --- a/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed +++ b/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed @@ -4,5 +4,5 @@ // Regression test for issue 79694 fn main() { - let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect + let _ = async move { }; //~ ERROR the order of `move` and `async` is incorrect } diff --git a/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs b/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs index 81ffbacc3273f..9c36a6c96da61 100644 --- a/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs +++ b/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs @@ -4,5 +4,5 @@ // Regression test for issue 79694 fn main() { - let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect + let _ = move async { }; //~ ERROR the order of `move` and `async` is incorrect } diff --git a/tests/ui/attributes/rustc_skip_during_method_dispatch.rs b/tests/ui/attributes/rustc_skip_during_method_dispatch.rs new file mode 100644 index 0000000000000..25b473d5a5851 --- /dev/null +++ b/tests/ui/attributes/rustc_skip_during_method_dispatch.rs @@ -0,0 +1,38 @@ +#![feature(rustc_attrs)] + +#[rustc_skip_during_method_dispatch] +//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input [E0539] +trait NotAList {} + +#[rustc_skip_during_method_dispatch = "array"] +//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input [E0539] +trait AlsoNotAList {} + +#[rustc_skip_during_method_dispatch()] +//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input +trait Argless {} + +#[rustc_skip_during_method_dispatch(array, boxed_slice, array)] +//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input +trait Duplicate {} + +#[rustc_skip_during_method_dispatch(slice)] +//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input +trait Unexpected {} + +#[rustc_skip_during_method_dispatch(array = true)] +//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input +trait KeyValue {} + +#[rustc_skip_during_method_dispatch("array")] +//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input +trait String {} + +#[rustc_skip_during_method_dispatch(array, boxed_slice)] +trait OK {} + +#[rustc_skip_during_method_dispatch(array)] +//~^ ERROR: attribute should be applied to a trait +impl OK for () {} + +fn main() {} diff --git a/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr new file mode 100644 index 0000000000000..2f5d79684899f --- /dev/null +++ b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr @@ -0,0 +1,76 @@ +error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input + --> $DIR/rustc_skip_during_method_dispatch.rs:3:1 + | +LL | #[rustc_skip_during_method_dispatch] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` + +error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input + --> $DIR/rustc_skip_during_method_dispatch.rs:7:1 + | +LL | #[rustc_skip_during_method_dispatch = "array"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` + +error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input + --> $DIR/rustc_skip_during_method_dispatch.rs:11:1 + | +LL | #[rustc_skip_during_method_dispatch()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--^ + | | | + | | expected at least 1 argument here + | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` + +error[E0538]: malformed `rustc_skip_during_method_dispatch` attribute input + --> $DIR/rustc_skip_during_method_dispatch.rs:15:1 + | +LL | #[rustc_skip_during_method_dispatch(array, boxed_slice, array)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^ + | | | + | | found `array` used as a key more than once + | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` + +error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input + --> $DIR/rustc_skip_during_method_dispatch.rs:19:1 + | +LL | #[rustc_skip_during_method_dispatch(slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^ + | | | + | | valid arguments are `array` or `boxed_slice` + | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` + +error[E0565]: malformed `rustc_skip_during_method_dispatch` attribute input + --> $DIR/rustc_skip_during_method_dispatch.rs:23:1 + | +LL | #[rustc_skip_during_method_dispatch(array = true)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` + +error[E0565]: malformed `rustc_skip_during_method_dispatch` attribute input + --> $DIR/rustc_skip_during_method_dispatch.rs:27:1 + | +LL | #[rustc_skip_during_method_dispatch("array")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ + | | | + | | didn't expect a literal here + | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` + +error: attribute should be applied to a trait + --> $DIR/rustc_skip_during_method_dispatch.rs:34:1 + | +LL | #[rustc_skip_during_method_dispatch(array)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl OK for () {} + | ----------------- not a trait + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0538, E0539, E0565. +For more information about an error, try `rustc --explain E0538`. diff --git a/tests/ui/compiletest-self-test/line-annotation-mismatches.rs b/tests/ui/compiletest-self-test/line-annotation-mismatches.rs new file mode 100644 index 0000000000000..d2a14374ed4c7 --- /dev/null +++ b/tests/ui/compiletest-self-test/line-annotation-mismatches.rs @@ -0,0 +1,42 @@ +//@ should-fail + +// The warning is reported with unknown line +//@ compile-flags: -D raw_pointer_derive +//~? WARN kind and unknown line match the reported warning, but we do not suggest it + +// The error is expected but not reported at all. +//~ ERROR this error does not exist + +// The error is reported but not expected at all. +// "`main` function not found in crate" (the main function is intentionally not added) + +// An "unimportant" diagnostic is expected on a wrong line. +//~ ERROR aborting due to + +// An "unimportant" diagnostic is expected with a wrong kind. +//~? ERROR For more information about an error + +fn wrong_line_or_kind() { + // A diagnostic expected on a wrong line. + unresolved1; + //~ ERROR cannot find value `unresolved1` in this scope + + // A diagnostic expected with a wrong kind. + unresolved2; //~ WARN cannot find value `unresolved2` in this scope + + // A diagnostic expected with a missing kind (treated as a wrong kind). + unresolved3; //~ cannot find value `unresolved3` in this scope + + // A diagnostic expected with a wrong line and kind. + unresolved4; + //~ WARN cannot find value `unresolved4` in this scope +} + +fn wrong_message() { + // A diagnostic expected with a wrong message, but the line is known and right. + unresolvedA; //~ ERROR stub message 1 + + // A diagnostic expected with a wrong message, but the line is known and right, + // even if the kind doesn't match. + unresolvedB; //~ WARN stub message 2 +} diff --git a/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr b/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr new file mode 100644 index 0000000000000..7ca3bfaf396c9 --- /dev/null +++ b/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr @@ -0,0 +1,61 @@ +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: `#[warn(renamed_and_removed_lints)]` on by default + +error[E0425]: cannot find value `unresolved1` in this scope + --> $DIR/line-annotation-mismatches.rs:21:5 + | +LL | unresolved1; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolved2` in this scope + --> $DIR/line-annotation-mismatches.rs:25:5 + | +LL | unresolved2; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolved3` in this scope + --> $DIR/line-annotation-mismatches.rs:28:5 + | +LL | unresolved3; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolved4` in this scope + --> $DIR/line-annotation-mismatches.rs:31:5 + | +LL | unresolved4; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolvedA` in this scope + --> $DIR/line-annotation-mismatches.rs:37:5 + | +LL | unresolvedA; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolvedB` in this scope + --> $DIR/line-annotation-mismatches.rs:41:5 + | +LL | unresolvedB; + | ^^^^^^^^^^^ not found in this scope + +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0601]: `main` function not found in crate `line_annotation_mismatches` + --> $DIR/line-annotation-mismatches.rs:42:2 + | +LL | } + | ^ consider adding a `main` function to `$DIR/line-annotation-mismatches.rs` + +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 7 previous errors; 3 warnings emitted + +Some errors have detailed explanations: E0425, E0601. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/deprecation/deprecated_no_stack_check.rs b/tests/ui/deprecation/deprecated_no_stack_check.rs index ef482098634a6..64635c5f5e88d 100644 --- a/tests/ui/deprecation/deprecated_no_stack_check.rs +++ b/tests/ui/deprecation/deprecated_no_stack_check.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![deny(warnings)] #![feature(no_stack_check)] diff --git a/tests/ui/feature-gates/feature-gate-cfi_encoding.rs b/tests/ui/feature-gates/feature-gate-cfi_encoding.rs index 3cef8156014bf..b6312dd7817f9 100644 --- a/tests/ui/feature-gates/feature-gate-cfi_encoding.rs +++ b/tests/ui/feature-gates/feature-gate-cfi_encoding.rs @@ -1,4 +1,4 @@ #![crate_type = "lib"] -#[cfi_encoding = "3Bar"] //~ERROR 3:1: 3:25: the `#[cfi_encoding]` attribute is an experimental feature [E0658] +#[cfi_encoding = "3Bar"] //~ ERROR the `#[cfi_encoding]` attribute is an experimental feature [E0658] pub struct Foo(i32); diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs index 2cf4b76180e15..67ac866803c06 100644 --- a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs +++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![crate_type = "lib"] #![feature(no_coverage)] //~ ERROR feature has been removed [E0557] diff --git a/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs b/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs index b5fbcc9ccf8c0..c146986379275 100644 --- a/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs +++ b/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs @@ -1,4 +1,4 @@ fn main() { let _ : &(dyn Send,) = &((),); - //~^ ERROR 2:28: 2:34: mismatched types [E0308] + //~^ ERROR mismatched types [E0308] } diff --git a/tests/ui/feature-gates/gated-bad-feature.rs b/tests/ui/feature-gates/gated-bad-feature.rs index 3114f661dc5bf..aa094acba374c 100644 --- a/tests/ui/feature-gates/gated-bad-feature.rs +++ b/tests/ui/feature-gates/gated-bad-feature.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] //~^ ERROR malformed `feature` //~| ERROR malformed `feature` diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs index ec6adb471ba50..a217a7fda51b4 100644 --- a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs +++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(external_doc)] //~ ERROR feature has been removed #![doc(include("README.md"))] //~ ERROR unknown `doc` attribute `include` diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.rs b/tests/ui/impl-header-lifetime-elision/assoc-type.rs index db3c416540fcd..14b2ea647f190 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.rs +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.rs @@ -9,7 +9,7 @@ trait MyTrait { impl MyTrait for &i32 { type Output = &i32; - //~^ ERROR 11:19: 11:20: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type } impl MyTrait for &u32 { diff --git a/tests/ui/imports/issue-28134.rs b/tests/ui/imports/issue-28134.rs index 70d3a327c1afa..aef2fe8facdcf 100644 --- a/tests/ui/imports/issue-28134.rs +++ b/tests/ui/imports/issue-28134.rs @@ -2,4 +2,4 @@ #![allow(soft_unstable)] #![test] -//~^ ERROR 4:1: 4:9: `test` attribute cannot be used at crate level +//~^ ERROR `test` attribute cannot be used at crate level diff --git a/tests/ui/inference/hint-closure-signature-119266.rs b/tests/ui/inference/hint-closure-signature-119266.rs index 35be600fd6ab8..6e136c57ccad3 100644 --- a/tests/ui/inference/hint-closure-signature-119266.rs +++ b/tests/ui/inference/hint-closure-signature-119266.rs @@ -3,7 +3,7 @@ fn main() { //~^ NOTE: the found closure let x: fn(i32) = x; - //~^ ERROR: 5:22: 5:23: mismatched types [E0308] + //~^ ERROR: mismatched types [E0308] //~| NOTE: incorrect number of function parameters //~| NOTE: expected due to this //~| NOTE: expected fn pointer `fn(i32)` diff --git a/tests/ui/integral-indexing.rs b/tests/ui/integral-indexing.rs index f076dfcb0a42c..e20553af8a26f 100644 --- a/tests/ui/integral-indexing.rs +++ b/tests/ui/integral-indexing.rs @@ -3,14 +3,14 @@ pub fn main() { let s: String = "abcdef".to_string(); v[3_usize]; v[3]; - v[3u8]; //~ERROR : the type `[isize]` cannot be indexed by `u8` - v[3i8]; //~ERROR : the type `[isize]` cannot be indexed by `i8` - v[3u32]; //~ERROR : the type `[isize]` cannot be indexed by `u32` - v[3i32]; //~ERROR : the type `[isize]` cannot be indexed by `i32` + v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8` + v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8` + v[3u32]; //~ ERROR the type `[isize]` cannot be indexed by `u32` + v[3i32]; //~ ERROR the type `[isize]` cannot be indexed by `i32` s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ERROR : the type `[u8]` cannot be indexed by `u8` - s.as_bytes()[3i8]; //~ERROR : the type `[u8]` cannot be indexed by `i8` - s.as_bytes()[3u32]; //~ERROR : the type `[u8]` cannot be indexed by `u32` - s.as_bytes()[3i32]; //~ERROR : the type `[u8]` cannot be indexed by `i32` + s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8` + s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8` + s.as_bytes()[3u32]; //~ ERROR the type `[u8]` cannot be indexed by `u32` + s.as_bytes()[3i32]; //~ ERROR the type `[u8]` cannot be indexed by `i32` } diff --git a/tests/ui/issues/issue-92741.rs b/tests/ui/issues/issue-92741.rs index f2e5fdafd9cb8..1c5d5810a57ee 100644 --- a/tests/ui/issues/issue-92741.rs +++ b/tests/ui/issues/issue-92741.rs @@ -1,17 +1,17 @@ //@ run-rustfix fn main() {} fn _foo() -> bool { - & //~ ERROR 4:5: 6:36: mismatched types [E0308] + & //~ ERROR mismatched types [E0308] mut if true { true } else { false } } fn _bar() -> bool { - & //~ ERROR 10:5: 11:40: mismatched types [E0308] + & //~ ERROR mismatched types [E0308] mut if true { true } else { false } } fn _baz() -> bool { - & mut //~ ERROR 15:5: 16:36: mismatched types [E0308] + & mut //~ ERROR mismatched types [E0308] if true { true } else { false } } diff --git a/tests/ui/lifetimes/no_lending_iterators.rs b/tests/ui/lifetimes/no_lending_iterators.rs index b3e8ad08ba18b..88b8cda0898be 100644 --- a/tests/ui/lifetimes/no_lending_iterators.rs +++ b/tests/ui/lifetimes/no_lending_iterators.rs @@ -2,7 +2,7 @@ struct Data(String); impl Iterator for Data { type Item = &str; - //~^ ERROR 4:17: 4:18: associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type fn next(&mut self) -> Option { Some(&self.0) @@ -16,7 +16,7 @@ trait Bar { impl Bar for usize { type Item = &usize; - //~^ ERROR 18:17: 18:18: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type fn poke(&mut self, item: Self::Item) { self += *item; @@ -25,7 +25,7 @@ impl Bar for usize { impl Bar for isize { type Item<'a> = &'a isize; - //~^ ERROR 27:14: 27:18: lifetime parameters or bounds on associated type `Item` do not match the trait declaration [E0195] + //~^ ERROR lifetime parameters or bounds on associated type `Item` do not match the trait declaration [E0195] fn poke(&mut self, item: Self::Item) { self += *item; diff --git a/tests/ui/macros/macro-reexport-removed.rs b/tests/ui/macros/macro-reexport-removed.rs index c1267f14cd868..33e7cab4068e2 100644 --- a/tests/ui/macros/macro-reexport-removed.rs +++ b/tests/ui/macros/macro-reexport-removed.rs @@ -1,5 +1,5 @@ //@ aux-build:two_macros.rs -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(macro_reexport)] //~ ERROR feature has been removed diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs index f589e88f68e44..0632b822c55c8 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -2,17 +2,17 @@ #![crate_type = "lib"] pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { - arg //~ ERROR 5:5: 5:8: mismatched types [E0308] + arg //~ ERROR mismatched types [E0308] } pub fn bar(arg: Option<&Vec>) -> &[i32] { - arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308] + arg.unwrap_or(&[]) //~ ERROR mismatched types [E0308] } pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { - arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308] + arg.unwrap_or(v) //~ ERROR mismatched types [E0308] } pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { - arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308] + arg.unwrap_or(&[]) //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs index 2257130280dcc..c0f3c190b65bc 100644 --- a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs +++ b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(doc_keyword)] //~ ERROR #![feature(doc_primitive)] //~ ERROR diff --git a/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs index 7ef6bd2f0acc3..23ffabad62fe8 100644 --- a/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs +++ b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs @@ -7,5 +7,5 @@ #![no_core] #![no_main] -#[cfi_encoding] //~ERROR 10:1: 10:16: malformed `cfi_encoding` attribute input +#[cfi_encoding] //~ ERROR malformed `cfi_encoding` attribute input pub struct Type1(i32); diff --git a/tests/ui/suggestions/issue-105645.rs b/tests/ui/suggestions/issue-105645.rs index 681ce1c6e37a6..f3ca8ccbb3c71 100644 --- a/tests/ui/suggestions/issue-105645.rs +++ b/tests/ui/suggestions/issue-105645.rs @@ -2,7 +2,7 @@ fn main() { let mut buf = [0u8; 50]; let mut bref = buf.as_slice(); foo(&mut bref); - //~^ ERROR 4:9: 4:18: the trait bound `&[u8]: std::io::Write` is not satisfied [E0277] + //~^ ERROR the trait bound `&[u8]: std::io::Write` is not satisfied [E0277] } fn foo(_: &mut impl std::io::Write) {} diff --git a/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs b/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs index 1dfc0786668f2..807fba0ab7e71 100644 --- a/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs +++ b/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs @@ -6,5 +6,5 @@ mod option { } fn main() { - let _: option::O<()> = (); //~ ERROR 9:28: 9:30: mismatched types [E0308] + let _: option::O<()> = (); //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs index b563b78f78a16..9a41b9c8173af 100644 --- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs +++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs @@ -6,7 +6,7 @@ // Regression test for issue #125877. //@ compile-flags: -Znext-solver -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(const_trait_impl, effects)] //~^ ERROR feature has been removed diff --git a/tests/ui/type/option-ref-advice.rs b/tests/ui/type/option-ref-advice.rs index 2dcee5a2eb912..435b15d01e3c3 100644 --- a/tests/ui/type/option-ref-advice.rs +++ b/tests/ui/type/option-ref-advice.rs @@ -3,9 +3,9 @@ fn takes_option(_arg: Option<&String>) {} fn main() { - takes_option(&None); //~ ERROR 6:18: 6:23: mismatched types [E0308] + takes_option(&None); //~ ERROR mismatched types [E0308] let x = String::from("x"); let res = Some(x); - takes_option(&res); //~ ERROR 10:18: 10:22: mismatched types [E0308] + takes_option(&res); //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/typeck/issue-100246.rs b/tests/ui/typeck/issue-100246.rs index 8f0b34bab0c87..e05bb2a1362a5 100644 --- a/tests/ui/typeck/issue-100246.rs +++ b/tests/ui/typeck/issue-100246.rs @@ -25,6 +25,6 @@ fn downcast<'a, W: ?Sized>() -> std::io::Result<&'a W> { struct Other; fn main() -> std::io::Result<()> { - let other: Other = downcast()?;//~ERROR 28:24: 28:35: `?` operator has incompatible types + let other: Other = downcast()?; //~ ERROR `?` operator has incompatible types Ok(()) } diff --git a/tests/ui/typeck/issue-89275.rs b/tests/ui/typeck/issue-89275.rs index b91c001754872..6e4211de1857f 100644 --- a/tests/ui/typeck/issue-89275.rs +++ b/tests/ui/typeck/issue-89275.rs @@ -25,5 +25,5 @@ fn downcast<'a, W: ?Sized>() -> &'a W { struct Other; fn main() { - let other: &mut Other = downcast();//~ERROR 28:29: 28:39: mismatched types [E0308] + let other: &mut Other = downcast();//~ ERROR mismatched types [E0308] } diff --git a/tests/ui/unsized-locals/yote.rs b/tests/ui/unsized-locals/yote.rs index aa5b68a307820..f09db9dd006c9 100644 --- a/tests/ui/unsized-locals/yote.rs +++ b/tests/ui/unsized-locals/yote.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(unsized_locals)] //~ERROR feature has been removed #![crate_type = "lib"]