diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index e72533fb3c890..05e1557f58b60 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -91,7 +91,7 @@ fn parse_unstable( for param in list.mixed() { let param_span = param.span(); - if let Some(ident) = param.meta_item().and_then(|i| i.path().word()) { + if let Some(ident) = param.meta_item_no_args().and_then(|i| i.path().word()) { res.push(ident.name); } else { cx.emit_err(session_diagnostics::ExpectsFeatures { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 41abb4806567f..94cc2cf76d6c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -26,7 +26,7 @@ impl SingleAttributeParser for OptimizeParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let single = cx.expect_single_element_list(args, cx.attr_span)?; - let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) { + let res = match single.meta_item_no_args().and_then(|i| i.path().word().map(|i| i.name)) { Some(sym::size) => OptimizeAttr::Size, Some(sym::speed) => OptimizeAttr::Speed, Some(sym::none) => OptimizeAttr::DoNotOptimize, @@ -80,7 +80,7 @@ impl SingleAttributeParser for CoverageParser { let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]); - let Some(arg) = arg.meta_item() else { + let Some(arg) = arg.meta_item_no_args() else { fail_incorrect_argument(arg.span()); return None; }; @@ -373,7 +373,7 @@ impl AttributeParser for UsedParser { return; }; - match l.meta_item().and_then(|i| i.path().word_sym()) { + match l.meta_item_no_args().and_then(|i| i.path().word_sym()) { Some(sym::compiler) => { if !cx.features().used_with_arg() { feature_err( diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index e783e49ef1e83..4379563873f4d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -17,6 +17,7 @@ impl AttributeParser for OnConstParser { |this, cx, args| { if !cx.features().diagnostic_on_const() { // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs + args.ignore_args(); return; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index b3c6c93a480ee..f08d983d47efc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -20,6 +20,7 @@ impl OnMoveParser { fn parse<'sess>(&mut self, cx: &mut AcceptContext<'_, 'sess>, args: &ArgParser, mode: Mode) { if !cx.features().diagnostic_on_move() { // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs + args.ignore_args(); return; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index 4c327804dd5b9..43d2ead682852 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -18,6 +18,7 @@ impl OnUnknownParser { && !features.diagnostic_on_unknown() { // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs + args.ignore_args(); return; } let span = cx.attr_span; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 535f67f67a263..f31af01e0e77e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -190,6 +190,8 @@ impl DocParser { // FIXME: convert list into a Vec of `AttributeKind` because current code is awful. for attr in list.mixed() { + // Arguments of `attr` are checked via the span, so can be safely ignored + attr.ignore_args(); self.attribute.test_attrs.push(attr.span()); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 622f7e1ceba49..ebf72722c9012 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -14,7 +14,8 @@ impl SingleAttributeParser for RustcDummyParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really - fn convert(_: &mut AcceptContext<'_, '_>, _: &ArgParser) -> Option { + fn convert(_: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { + args.ignore_args(); Some(AttributeKind::RustcDummy) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index aee0537771fd4..9363ae2bf286f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -39,7 +39,7 @@ impl SingleAttributeParser for InlineParser { ArgParser::List(list) => { let l = cx.expect_single(list)?; - match l.meta_item().and_then(|i| i.path().word_sym()) { + match l.meta_item_no_args().and_then(|i| i.path().word_sym()) { Some(sym::always) => { Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 6f239a8f5761d..a42a77d95c5c0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -21,7 +21,7 @@ impl SingleAttributeParser for InstructionSetParser { const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32]; let maybe_meta_item = cx.expect_single_element_list(args, cx.attr_span)?; - let Some(meta_item) = maybe_meta_item.meta_item() else { + let Some(meta_item) = maybe_meta_item.meta_item_no_args() else { cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 067590d23fc8d..ff0ab2747962f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -145,7 +145,7 @@ impl SingleAttributeParser for MacroExportParser { cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; }; - match l.meta_item().and_then(|i| i.path().word_sym()) { + match l.meta_item_no_args().and_then(|i| i.path().word_sym()) { Some(sym::local_inner_macros) => true, _ => { cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 8d507065dbdb6..4adbcbbdf6587 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -98,7 +98,7 @@ impl CombineAttributeParser for RustcDumpLayoutParser { let mut result = Vec::new(); for item in items.mixed() { - let Some(arg) = item.meta_item() else { + let Some(arg) = item.meta_item_no_args() else { cx.adcx().expected_not_literal(item.span()); continue; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 8a648550ae8c6..3192f9c767fc1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -43,7 +43,7 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser { let mut errored = false; for argument in inputs { - let Some(meta) = argument.meta_item() else { + let Some(meta) = argument.meta_item_no_args() else { cx.adcx().expected_identifier(argument.span()); return None; }; @@ -820,7 +820,7 @@ impl SingleAttributeParser for RustcIfThisChangedParser { ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)), ArgParser::List(list) => { let item = cx.expect_single(list)?; - let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { + let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else { cx.adcx().expected_identifier(item.span()); return None; }; @@ -878,7 +878,7 @@ impl CombineAttributeParser for RustcThenThisWouldNeedParser { cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" }); } let item = cx.expect_single_element_list(args, cx.attr_span)?; - let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { + let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else { cx.adcx().expected_identifier(item.span()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 7ffeb3d2194a3..eeee6eff00931 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -123,7 +123,7 @@ impl SingleAttributeParser for RustcAbiParser { let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]); - let Some(arg) = arg.meta_item() else { + let Some(arg) = arg.meta_item_no_args() else { fail_incorrect_argument(args.span); return None; }; @@ -173,7 +173,7 @@ impl SingleAttributeParser for TestRunnerParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let single = cx.expect_single_element_list(args, cx.attr_span)?; - let Some(meta) = single.meta_item() else { + let Some(meta) = single.meta_item_no_args() else { cx.adcx().expected_not_literal(single.span()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 750fe10a483fc..8da222e58496a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -4,6 +4,8 @@ use std::collections::btree_map::Entry; use std::mem; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast::{AttrStyle, MetaItemLit, Safety}; use rustc_data_structures::sync::{DynSend, DynSync}; @@ -405,6 +407,8 @@ impl<'f, 'sess: 'f> SharedContext<'f, 'sess> { kind: EmitAttribute, span: impl Into, ) { + #[cfg(debug_assertions)] + self.has_lint_been_emitted.store(true, Ordering::Relaxed); if !matches!( self.should_emit, ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true } @@ -744,6 +748,11 @@ pub struct SharedContext<'p, 'sess> { pub(crate) target: rustc_hir::Target, pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, EmitAttribute), + + /// This atomic bool keeps track of whether any lint has been emitted. + /// This is used for the arguments-used check. + #[cfg(debug_assertions)] + pub(crate) has_lint_been_emitted: AtomicBool, } /// Context given to every attribute parser during finalization. diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 052bccfde8359..7af02258d0550 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,4 +1,6 @@ use std::convert::identity; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; @@ -228,6 +230,8 @@ impl<'sess> AttributeParser<'sess> { target_span, target, emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: AtomicBool::new(false), }, attr_span, inner_span, @@ -395,6 +399,8 @@ impl<'sess> AttributeParser<'sess> { target_span, target, emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: AtomicBool::new(false), }, attr_span, inner_span, @@ -409,6 +415,10 @@ impl<'sess> AttributeParser<'sess> { finalizers.push(accept.finalizer); Self::check_target(&accept.allowed_targets, &mut cx); + #[cfg(debug_assertions)] + if !cx.shared.has_lint_been_emitted.load(Ordering::Relaxed) { + cx.shared.cx.check_args_used(&attr, &args) + } } else { let attr = AttrItem { path: attr_path.clone(), @@ -442,7 +452,14 @@ impl<'sess> AttributeParser<'sess> { early_parsed_state.finalize_early_parsed_attributes(&mut attributes); for f in &finalizers { if let Some(attr) = f(&mut FinalizeContext { - shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint }, + shared: SharedContext { + cx: self, + target_span, + target, + emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: AtomicBool::new(false), + }, all_attrs: &attr_paths, }) { attributes.push(Attribute::Parsed(attr)); @@ -456,6 +473,26 @@ impl<'sess> AttributeParser<'sess> { attributes } + #[cfg(debug_assertions)] + /// Checks whether all `ArgParser`s were observed by an attribute parser at least once + /// This check exists because otherwise it is too easy to accidentally ignore the arguments of an attribute + fn check_args_used(&self, attr: &ast::Attribute, args: &ArgParser) { + if let ArgParser::List(items) = args { + for item in items.mixed() { + if let crate::parser::MetaItemOrLitParser::MetaItemParser(item) = item { + if !item.are_args_checked() { + self.dcx().span_delayed_bug( + item.span(), + "attribute args were not properly checked", + ); + return; + } + self.check_args_used(attr, item.args()); + } + } + } + } + /// Returns whether there is a parser for an attribute with this name pub fn is_parsed_attribute(path: &[Symbol]) -> bool { /// The list of attributes that are parsed attributes, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 15a9eb91a143d..820400813f910 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -5,6 +5,8 @@ use std::borrow::Borrow; use std::fmt::{Debug, Display}; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; @@ -87,7 +89,7 @@ impl> Display for PathParser

{ } } -#[derive(Clone, Debug)] +#[derive(Debug)] #[must_use] pub enum ArgParser { NoArgs, @@ -209,13 +211,26 @@ impl ArgParser { Self::NameValue(args) => Err(args.args_span()), } } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + #[cfg(debug_assertions)] + match self { + ArgParser::List(list) => { + for item in list.mixed() { + item.ignore_args(); + } + } + _ => {} + } + } } /// Inside lists, values could be either literals, or more deeply nested meta items. /// This enum represents that. /// /// Choose which one you want using the provided methods. -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum MetaItemOrLitParser { MetaItemParser(MetaItemParser), Lit(MetaItemLit), @@ -253,6 +268,26 @@ impl MetaItemOrLitParser { MetaItemOrLitParser::Lit(_) => None, } } + + /// Returns some if this `MetaItemOrLitParser` is a `MetaItem` with no arguments + pub fn meta_item_no_args(&self) -> Option<&MetaItemParser> { + let meta_item = self.meta_item()?; + match meta_item.args().as_no_args() { + Ok(_) => Some(meta_item), + Err(_) => None, + } + } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + #[cfg(debug_assertions)] + match self { + MetaItemOrLitParser::MetaItemParser(meta_item) => { + meta_item.ignore_args(); + } + MetaItemOrLitParser::Lit(_) => {} + } + } } // FIXME(scrabsha): once #155696 is merged, update this and mention the higher-level APIs. @@ -270,10 +305,14 @@ impl MetaItemOrLitParser { /// `= value` part /// /// The syntax of MetaItems can be found at -#[derive(Clone)] pub struct MetaItemParser { path: OwnedPathParser, args: ArgParser, + + /// Whether the `args` of this meta item have been looked at. + /// This is tracked because if the arguments of a `MetaItemParser` are ignored, this is probably a mistake + #[cfg(debug_assertions)] + args_checked: AtomicBool, } impl Debug for MetaItemParser { @@ -310,6 +349,8 @@ impl MetaItemParser { /// Gets just the args parser, without caring about the path. pub fn args(&self) -> &ArgParser { + #[cfg(debug_assertions)] + self.args_checked.store(true, Ordering::Relaxed); &self.args } @@ -322,6 +363,16 @@ impl MetaItemParser { pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> { self.path().word_is(sym).then(|| self.args()) } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + self.args().ignore_args(); + } + + #[cfg(debug_assertions)] + pub fn are_args_checked(&self) -> bool { + self.args_checked.load(Ordering::Relaxed) + } } #[derive(Clone)] @@ -545,7 +596,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { ArgParser::NoArgs }; - Ok(MetaItemParser { path: PathParser(path), args }) + Ok(MetaItemParser { + path: PathParser(path), + args, + #[cfg(debug_assertions)] + args_checked: AtomicBool::new(false), + }) } fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { @@ -670,7 +726,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct MetaItemListParser { sub_parsers: ThinVec, pub span: Span, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b6b95c5f12aae..0eaad18430c2b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1737,7 +1737,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { op.store_with_annotation(bx, scratch); (scratch.val.llval, scratch.val.align, true) } - _ => (op.immediate_or_packed_pair(bx), arg.layout.align.abi, false), + PassMode::Direct(_) => (op.immediate(), arg.layout.align.abi, false), + PassMode::Ignore | PassMode::Pair(..) => unreachable!("handled above"), }, Ref(op_place_val) => match arg.mode { PassMode::Indirect { attrs, on_stack, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 4bcf037ecce07..0abdef85b1980 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -499,9 +499,12 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( PassMode::Direct(_) => { let llarg = bx.get_param(llarg_idx); llarg_idx += 1; - return local(OperandRef::from_immediate_or_packed_pair( - bx, llarg, arg.layout, - )); + debug_assert!(bx.is_backend_immediate(arg.layout)); + return local(OperandRef { + val: OperandValue::Immediate(llarg), + layout: arg.layout, + move_annotation: None, + }); } PassMode::Pair(..) => { let (a, b) = (bx.get_param(llarg_idx), bx.get_param(llarg_idx + 1)); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index c0c71edd4d905..68a84ebdae9fc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -306,6 +306,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { /// If this operand is a `Pair`, we return an aggregate with the two values. /// For other cases, see `immediate`. + /// + /// Note: The use of this is discouraged outside cg_llvm, as some other backends + /// don't natively support packing multiple things into one like this. pub fn immediate_or_packed_pair>( self, bx: &mut Bx, @@ -324,6 +327,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`. + /// + /// Note: The use of this is discouraged outside cg_llvm, as some other backends + /// don't natively support packing multiple things into one like this. pub fn from_immediate_or_packed_pair>( bx: &mut Bx, llval: V, diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 6aa88b86e4e60..40ba31d37f2f0 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -272,8 +272,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { caller_args: &mut impl Iterator< Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), >, - callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, - callee_arg_idx: usize, + callee_args_abis: &mut impl Iterator>)>, callee_arg: &mir::Place<'tcx>, callee_ty: Ty<'tcx>, already_live: bool, @@ -282,15 +281,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { 'tcx: 'x, 'tcx: 'y, { + // Get next callee arg. + let (callee_arg_idx, callee_abi) = callee_args_abis.next().unwrap(); assert_eq!(callee_ty, callee_abi.layout.ty); - if callee_abi.is_ignore() { - // This one is skipped. Still must be made live though! - if !already_live { - self.storage_live(callee_arg.as_local().unwrap())?; - } - return interp_ok(()); - } - // Find next caller arg. + // Get next caller arg. let Some((caller_arg, caller_abi)) = caller_args.next() else { throw_ub_format!("calling a function with fewer arguments than it requires"); }; @@ -348,6 +342,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mut cont: ReturnContinuation, ) -> InterpResult<'tcx> { let _trace = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty); + let def_id = instance.def_id(); // The first order of business is to figure out the callee signature. // However, that requires the list of variadic arguments. @@ -423,10 +418,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { "spread_arg: {:?}, locals: {:#?}", body.spread_arg, body.args_iter() - .map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty,)) + .map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty)) .collect::>() ); + // Determine whether there is a special VaList argument. This is always the + // last argument, and since arguments start at index 1 that's `arg_count`. + let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); + // Determine whether this is a non-capturing closure. That's relevant as their first + // argument can be skipped (and that's the only kind of argument skipping we allow). + let is_non_capturing_closure = + (matches!(instance.def, ty::InstanceKind::ClosureOnceShim { .. }) + || self.tcx.is_closure_like(def_id)) + && { + let arg = &callee_fn_abi.args[0]; + matches!(arg.layout.ty.kind(), ty::Closure (_def, closure_args) if { + closure_args.as_closure().upvar_tys().is_empty() + }) + }; + // In principle, we have two iterators: Where the arguments come from, and where // they go to. @@ -439,21 +449,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { caller_fn_abi.args.len(), "mismatch between caller ABI and caller arguments", ); - let mut caller_args = args - .iter() - .zip(caller_fn_abi.args.iter()) - .filter(|arg_and_abi| !arg_and_abi.1.is_ignore()); + let mut caller_args = args.iter().zip(caller_fn_abi.args.iter()); // Now we have to spread them out across the callee's locals, // taking into account the `spread_arg`. If we could write // this is a single iterator (that handles `spread_arg`), then - // `pass_argument` would be the loop body. It takes care to - // not advance `caller_iter` for ignored arguments. + // `pass_argument` would be the loop body. let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); - // Determine whether there is a special VaList argument. This is always the - // last argument, and since arguments start at index 1 that's `arg_count`. - let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count)); - // During argument passing, we want retagging with protectors. M::with_retag_mode(self, RetagMode::FnEntry, |ecx| { for local in body.args_iter() { @@ -466,7 +468,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // type, but the result gets cached so this avoids calling the instantiation // query *again* the next time this local is accessed. let ty = ecx.layout_of_local(ecx.frame(), local, None)?.ty; - if Some(local) == va_list_arg { + + // Some arguments are special: the first (`self`) argument of a non-capturing + // closure; the va_list argument; and the spread_arg. + if is_non_capturing_closure && local == mir::Local::arg(0) { + assert!(va_list_arg.is_none()); + assert!(Some(local) != body.spread_arg); + // This argument might be missing on the caller side. So just initialize it in + // the callee. + let (callee_arg_idx, callee_abi) = callee_args_abis.next().unwrap(); + assert!(callee_abi.layout.is_1zst() && callee_abi.is_ignore()); + ecx.storage_live(local)?; + // And skip it in the caller, if present. We can tell whether it is present by + // comparing the number of arguments on the caller and callee side. + if caller_fn_abi.args.len() == callee_fn_abi.args.len() { + let (_caller_arg, caller_abi) = caller_args.next().unwrap(); + if !caller_abi.layout.is_1zst() { + // The caller gave us some other, non-ignorable argument. + throw_ub!(AbiMismatchArgument { + arg_idx: callee_arg_idx, + caller_ty: caller_abi.layout.ty, + callee_ty: callee_abi.layout.ty + }); + } + assert!(caller_abi.is_ignore()); + } + } else if Some(local) == va_list_arg { // This is the last callee-side argument of a variadic function. // This argument is a VaList holding the remaining caller-side arguments. ecx.storage_live(local)?; @@ -476,12 +503,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Consume the remaining arguments by putting them into the variable argument // list. - let varargs = ecx.allocate_varargs( - &mut caller_args, - // "Ignored" arguments aren't actually passed, so the callee should also - // ignore them. (`pass_argument` does this for regular arguments.) - (&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()), - )?; + let varargs = ecx.allocate_varargs(&mut caller_args, &mut callee_args_abis)?; // When the frame is dropped, these variable arguments are deallocated. ecx.frame_mut().va_list = varargs.clone(); let key = ecx.va_list_ptr(varargs.into()); @@ -507,11 +529,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], *ecx.tcx, ); - let (idx, callee_abi) = callee_args_abis.next().unwrap(); ecx.pass_argument( &mut caller_args, - callee_abi, - idx, + &mut callee_args_abis, &dest, field_ty, /* already_live */ true, @@ -519,11 +539,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } else { // Normal argument. Cannot mark it as live yet, it might be unsized! - let (idx, callee_abi) = callee_args_abis.next().unwrap(); ecx.pass_argument( &mut caller_args, - callee_abi, - idx, + &mut callee_args_abis, &dest, ty, /* already_live */ false, diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 97e739a7f3893..8b37ee2835e6c 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -252,7 +252,9 @@ impl Definitions { self.def_id_to_key[id] } - #[instrument(level = "trace", skip(self), ret)] + // Log debug version of `local_def_index` (just a number), as tracing of this function + // is called too early and cause errors if `LocalDefId` is logged (#157238). + #[instrument(level = "trace", skip(self, id), fields(def_index=?id.local_def_index), ret)] #[inline(always)] pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash { DefPathHash::new(self.stable_crate_id, self.def_path_hashes[id]) diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index bcda315f7a4a0..5c12600eac19d 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -1,5 +1,5 @@ use crate::iter::FusedIterator; -use crate::mem::{MaybeUninit, SizedTypeProperties}; +use crate::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; use crate::{fmt, ptr}; /// An iterator over the mapped windows of another iterator. @@ -30,14 +30,17 @@ struct MapWindowsInner { buffer: Option>, } -// `Buffer` uses two times of space to reduce moves among the iterations. -// `Buffer` is semantically `[MaybeUninit; 2 * N]`. However, due -// to limitations of const generics, we use this different type. Note that -// it has the same underlying memory layout. +/// `Buffer` is semantically `[MaybeUninit; 2 * N]`. This helps +/// reduce moves while iterating. However, due +/// to limitations of const generics, we use this different type. Note that +/// it has the same underlying memory layout. +/// +/// # Safety invariant +/// +/// `self.buffer[self.start..self.start + N]` must be initialized, +/// with all other elements being uninitialized. This also +/// implies that `self.start <= N`. struct Buffer { - // Invariant: `self.buffer[self.start..self.start + N]` is initialized, - // with all other elements being uninitialized. This also - // implies that `self.start <= N`. buffer: [[MaybeUninit; N]; 2], start: usize, } @@ -194,12 +197,18 @@ impl Buffer { impl Clone for Buffer { fn clone(&self) -> Self { - let mut buffer = Buffer { + // Use `ManuallyDrop` until buffer is fully written to avoid dropping uninitialized elements on panic. + // (See `Buffer` rustdoc for safety invariant) + let mut buffer = ManuallyDrop::new(Buffer { buffer: [[const { MaybeUninit::uninit() }; N], [const { MaybeUninit::uninit() }; N]], start: self.start, - }; + }); + + // `clone()` could panic; `ManuallyDrop` guards against that. buffer.as_uninit_array_mut().write(self.as_array_ref().clone()); - buffer + + // We initialized the buffer above, so we are good now + ManuallyDrop::into_inner(buffer) } } diff --git a/library/coretests/tests/iter/adapters/map_windows.rs b/library/coretests/tests/iter/adapters/map_windows.rs index 994ec087e5e8b..fa84f9d1c9cb4 100644 --- a/library/coretests/tests/iter/adapters/map_windows.rs +++ b/library/coretests/tests/iter/adapters/map_windows.rs @@ -5,7 +5,7 @@ use std::sync::atomic::Ordering::SeqCst; mod drop_checks { //! These tests mainly make sure the elements are correctly dropped. - use std::sync::atomic::Ordering::SeqCst; + use std::sync::atomic::Ordering::{Relaxed, SeqCst}; use std::sync::atomic::{AtomicBool, AtomicUsize}; #[derive(Debug)] @@ -143,6 +143,51 @@ mod drop_checks { check::<5>(5, 1); check::<5>(5, 4); } + + /// Regression test for #156501 + #[test] + fn panicking_clone() { + static CLONE_COUNTER: AtomicUsize = AtomicUsize::new(0); + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct PanickingClone(u8); + + impl Clone for PanickingClone { + fn clone(&self) -> Self { + if CLONE_COUNTER.fetch_add(1, Relaxed) == 3 { + panic!( + "⚞(· <:::> ·)⚟ aaaaaah its the turbofish monster!!! its gonna eat us all!!!1!" + ); + } + + Self(self.0) + } + } + + impl Drop for PanickingClone { + fn drop(&mut self) { + assert_eq!(self.0, 42); + + DROP_COUNTER.fetch_add(1, Relaxed); + } + } + + let array = [const { PanickingClone(42) }; 17]; + let mut iter = array.into_iter().map_windows::<_, (), 17>(|_| ()); + + // initialize the buffer + iter.next(); + + let result = std::panic::catch_unwind(|| { + // now do the clones and panic. + // this should't try to drop uninitialized memory + let _ = iter.clone(); + }); + + assert!(result.is_err()); + + assert_eq!(DROP_COUNTER.load(Relaxed), 3); + } } #[test] diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index bd198b726c6ad..62afcfe6af25f 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -2363,6 +2363,9 @@ fn test_fs_set_times_follows_symlink() { use crate::os::windows::fs::FileTimesExt; let tmp = tmpdir(); + if !got_symlink_permission(&tmp) { + return; + } // Create a target file let target = tmp.join("target"); @@ -2461,6 +2464,9 @@ fn test_fs_set_times_nofollow() { use crate::os::windows::fs::FileTimesExt; let tmp = tmpdir(); + if !got_symlink_permission(&tmp) { + return; + } // Create a target file and a symlink to it let target = tmp.join("target"); diff --git a/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs new file mode 100644 index 0000000000000..77dab904fdbba --- /dev/null +++ b/src/tools/miri/tests/fail/c-variadic-ignored-argument.rs @@ -0,0 +1,13 @@ +#![feature(c_variadic)] + +// While 1-ZST are currently ignored on most ABIs, we don't guarantee that, and it's UB to +// rely on it. + +fn main() { + unsafe extern "C" fn variadic(mut ap: ...) { + ap.next_arg::(); + ap.next_arg::(); //~ERROR: requested `i32` is incompatible with next argument of type `()` + } + + unsafe { variadic(0i32, (), 1i32) } +} diff --git a/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr b/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr new file mode 100644 index 0000000000000..6c1291611c4ae --- /dev/null +++ b/src/tools/miri/tests/fail/c-variadic-ignored-argument.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: va_arg type mismatch: requested `i32` is incompatible with next argument of type `()` + --> tests/fail/c-variadic-ignored-argument.rs:LL:CC + | +LL | ap.next_arg::(); + | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: main::variadic + at tests/fail/c-variadic-ignored-argument.rs:LL:CC + 1: main + at tests/fail/c-variadic-ignored-argument.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs new file mode 100644 index 0000000000000..064b5a510f3ea --- /dev/null +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs @@ -0,0 +1,19 @@ +#![feature(fn_traits, unboxed_closures)] + +use std::mem::transmute; + +#[repr(align(4))] +struct Zst; + +fn foo(_: F) { + // Calls the given F FnOnce, but passing an over-aligned ZST instead of the closure / function item + let f = unsafe { transmute::(F::call_once) }; + f(Zst) +} + +fn main() { + foo(move || { + //~^ERROR: /calling a function whose parameter #1 has type .* passing argument of type Zst/ + println!("non-capturing closure"); + }); +} diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr new file mode 100644 index 0000000000000..56f56e606f79d --- /dev/null +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_closure_non_capturing.stderr @@ -0,0 +1,26 @@ +error: Undefined Behavior: calling a function whose parameter #1 has type {closure@tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC} passing argument of type Zst + --> tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + | +LL | foo(move || { + | _________^ +LL | | +LL | | println!("non-capturing closure"); +LL | | }); + | |_____^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets + = help: if you think this code should be accepted anyway, please report an issue with Miri + = note: stack backtrace: + 0: main::{closure#0} + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + 1: foo::<{closure@tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC}> + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + 2: main + at tests/fail/function_pointers/abi_mismatch_closure_non_capturing.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs b/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs new file mode 100644 index 0000000000000..a6ffb325191b0 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/fn_arg_never_type.rs @@ -0,0 +1,13 @@ +use std::mem::transmute; + +enum Never {} + +fn foo(x: Never) { //~ERROR: invalid value of type Never + let ptr = &raw const x; + println!("{ptr:p}"); +} + +fn main() { + let f = unsafe { transmute::(foo) }; + f(()); +} diff --git a/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr b/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr new file mode 100644 index 0000000000000..2995492bc9456 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/fn_arg_never_type.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: constructing invalid value of type Never: encountered a value of zero-variant enum `Never` + --> tests/fail/validity/fn_arg_never_type.rs:LL:CC + | +LL | fn foo(x: Never) { + | ^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: stack backtrace: + 0: foo + at tests/fail/validity/fn_arg_never_type.rs:LL:CC + 1: main + at tests/fail/validity/fn_arg_never_type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs b/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs deleted file mode 100644 index fe09a03edfffc..0000000000000 --- a/src/tools/miri/tests/pass/c-variadic-ignored-argument.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ ignore-target: windows # does not ignore ZST arguments -//@ ignore-target: powerpc # does not ignore ZST arguments -//@ ignore-target: s390x # does not ignore ZST arguments -//@ ignore-target: sparc # does not ignore ZST arguments -#![feature(c_variadic)] - -// Some platforms ignore ZSTs, meaning that the argument is not passed, even though it is part -// of the callee's ABI. Test that this doesn't trip any asserts. -// -// NOTE: this test only succeeds when the `()` argument uses `Passmode::Ignore`. For some targets, -// notably msvc, such arguments are not ignored, which would cause UB when attempting to read the -// second `i32` argument while the next item in the variable argument list is `()`. - -fn main() { - unsafe extern "C" fn variadic(mut ap: ...) { - ap.next_arg::(); - ap.next_arg::(); - } - - unsafe { variadic(0i32, (), 1i32) } -} diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index 37795daa55c84..94cb5695fac50 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -151,4 +151,9 @@ fn main() { let rc = Rc::new(0); let rc_ptr: *mut i32 = unsafe { mem::transmute_copy(&rc) }; test_abi_compat(rc, rc_ptr); + + // Non-capturing closures are special because we rely on them being `PassMode::Ignore`. + // Make sure that does not break newtype wrapping for them. + let non_capturing_closure = || {}; + test_abi_compat(non_capturing_closure.clone(), Wrapper(non_capturing_closure)); } diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix index 6ca8a7c4652d3..199b63e645230 100644 --- a/src/tools/nix-dev-shell/shell.nix +++ b/src/tools/nix-dev-shell/shell.nix @@ -2,7 +2,7 @@ pkgs ? import { }, }: let - inherit (pkgs.lib) lists attrsets; + inherit (pkgs.lib) lists attrsets makeLibraryPath; x = pkgs.callPackage ./x { }; inherit (x.passthru) cacert env; @@ -25,6 +25,6 @@ pkgs.mkShell { RUSTC_ICE = 0; SSL_CERT_FILE = cacert; # cargo seems to dlopen libcurl, so we need it in the ld library path - LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath [pkgs.stdenv.cc.cc.lib pkgs.curl]}"; + LD_LIBRARY_PATH = "${makeLibraryPath [pkgs.stdenv.cc.cc.lib pkgs.curl]}"; }; } diff --git a/src/tools/nix-dev-shell/x/default.nix b/src/tools/nix-dev-shell/x/default.nix index 9573ddd2825d6..915158080e421 100644 --- a/src/tools/nix-dev-shell/x/default.nix +++ b/src/tools/nix-dev-shell/x/default.nix @@ -1,5 +1,4 @@ { - pkgs, lib, stdenv, rustc, @@ -16,7 +15,6 @@ # LLVM Deps ninja, cmake, - glibc, }: stdenv.mkDerivation (self: { strictDeps = true; diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs new file mode 100644 index 0000000000000..18369acfea034 --- /dev/null +++ b/tests/ui/attributes/args-checked.rs @@ -0,0 +1,73 @@ +#![feature(rustc_attrs)] +#![feature(optimize_attribute)] +#![feature(coverage_attribute)] +#![feature(custom_test_frameworks)] +#![allow(unused_attributes)] + +#![test_runner(x = 5)] +//~^ ERROR malformed +#![test_runner(x(x,y,z))] +//~^ ERROR malformed + +#[inline(always = 5)] +//~^ ERROR malformed +#[inline(always(x, y, z))] +//~^ ERROR malformed +#[instruction_set(arm::a32 = 5)] +//~^ ERROR malformed +#[instruction_set(arm::a32(x, y, z))] +//~^ ERROR malformed +#[optimize(size = 5)] +//~^ ERROR malformed +#[optimize(size(x, y, z))] +//~^ ERROR malformed +//~| ERROR multiple `optimize` attributes +#[coverage(off = 5)] +//~^ ERROR malformed +#[coverage(off(x, y, z))] +//~^ ERROR malformed +#[rustc_abi(debug = 5)] +//~^ ERROR malformed +#[rustc_abi(debug(x, y, z))] +//~^ ERROR malformed +fn main() { + +} + +#[macro_export(local_inner_macros = 5)] +//~^ ERROR valid forms for the attribute are +//~| WARN previously accepted +#[macro_export(local_inner_macros(x, y, z))] +//~^ ERROR valid forms for the attribute are +//~| WARN previously accepted +macro_rules! m { + () => {}; +} + +#[rustc_allow_const_fn_unstable(x = 5)] +//~^ ERROR `rustc_allow_const_fn_unstable` expects feature names +#[rustc_allow_const_fn_unstable(x(x, y, z))] +//~^ ERROR `rustc_allow_const_fn_unstable` expects feature names +const fn g() {} + +#[used(always = 5)] +//~^ ERROR malformed +#[used(always(x, y, z))] +//~^ ERROR malformed +static H: u64 = 5; + +#[rustc_must_implement_one_of(eq = 5, neq)] +//~^ ERROR malformed +#[rustc_must_implement_one_of(eq(x, y, z), neq)] +//~^ ERROR malformed +trait T { + +} + +#[rustc_dump_layout(debug = 5)] +//~^ ERROR malformed +#[rustc_dump_layout(debug(x, y, z))] +//~^ ERROR malformed +enum E { + +} diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr new file mode 100644 index 0000000000000..277dd672fef22 --- /dev/null +++ b/tests/ui/attributes/args-checked.stderr @@ -0,0 +1,361 @@ +error[E0565]: malformed `test_runner` attribute input + --> $DIR/args-checked.rs:7:1 + | +LL | #![test_runner(x = 5)] + | ^^^^^^^^^^^^^^^-----^^ + | | + | didn't expect a literal here + | +help: must be of the form + | +LL - #![test_runner(x = 5)] +LL + #![test_runner(path)] + | + +error[E0565]: malformed `test_runner` attribute input + --> $DIR/args-checked.rs:9:1 + | +LL | #![test_runner(x(x,y,z))] + | ^^^^^^^^^^^^^^^--------^^ + | | + | didn't expect a literal here + | +help: must be of the form + | +LL - #![test_runner(x(x,y,z))] +LL + #![test_runner(path)] + | + +error[E0539]: malformed `inline` attribute input + --> $DIR/args-checked.rs:12:1 + | +LL | #[inline(always = 5)] + | ^^^^^^^^^----------^^ + | | + | valid arguments are `always` or `never` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(always = 5)] +LL + #[inline(always)] + | +LL - #[inline(always = 5)] +LL + #[inline(never)] + | +LL - #[inline(always = 5)] +LL + #[inline] + | + +error[E0539]: malformed `inline` attribute input + --> $DIR/args-checked.rs:14:1 + | +LL | #[inline(always(x, y, z))] + | ^^^^^^^^^---------------^^ + | | + | valid arguments are `always` or `never` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(always(x, y, z))] +LL + #[inline(always)] + | +LL - #[inline(always(x, y, z))] +LL + #[inline(never)] + | +LL - #[inline(always(x, y, z))] +LL + #[inline] + | + +error[E0539]: malformed `instruction_set` attribute input + --> $DIR/args-checked.rs:16:1 + | +LL | #[instruction_set(arm::a32 = 5)] + | ^^^^^^^^^^^^^^^^^^------------^^ + | | + | valid arguments are `arm::a32` or `arm::t32` + | + = note: for more information, visit +help: must be of the form + | +LL - #[instruction_set(arm::a32 = 5)] +LL + #[instruction_set(set)] + | + +error[E0539]: malformed `instruction_set` attribute input + --> $DIR/args-checked.rs:18:1 + | +LL | #[instruction_set(arm::a32(x, y, z))] + | ^^^^^^^^^^^^^^^^^^-----------------^^ + | | + | valid arguments are `arm::a32` or `arm::t32` + | + = note: for more information, visit +help: must be of the form + | +LL - #[instruction_set(arm::a32(x, y, z))] +LL + #[instruction_set(set)] + | + +error[E0539]: malformed `optimize` attribute input + --> $DIR/args-checked.rs:20:1 + | +LL | #[optimize(size = 5)] + | ^^^^^^^^^^^--------^^ + | | + | valid arguments are `size`, `speed` or `none` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[optimize(size = 5)] +LL + #[optimize(none)] + | +LL - #[optimize(size = 5)] +LL + #[optimize(size)] + | +LL - #[optimize(size = 5)] +LL + #[optimize(speed)] + | + +error[E0539]: malformed `optimize` attribute input + --> $DIR/args-checked.rs:22:1 + | +LL | #[optimize(size(x, y, z))] + | ^^^^^^^^^^^-------------^^ + | | + | valid arguments are `size`, `speed` or `none` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(none)] + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(size)] + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(speed)] + | + +error: multiple `optimize` attributes + --> $DIR/args-checked.rs:22:1 + | +LL | #[optimize(size(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/args-checked.rs:20:1 + | +LL | #[optimize(size = 5)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0539]: malformed `coverage` attribute input + --> $DIR/args-checked.rs:25:1 + | +LL | #[coverage(off = 5)] + | ^^^^^^^^^^^-------^^ + | | + | valid arguments are `on` or `off` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off = 5)] +LL + #[coverage(off)] + | +LL - #[coverage(off = 5)] +LL + #[coverage(on)] + | + +error[E0539]: malformed `coverage` attribute input + --> $DIR/args-checked.rs:27:1 + | +LL | #[coverage(off(x, y, z))] + | ^^^^^^^^^^^------------^^ + | | + | valid arguments are `on` or `off` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off(x, y, z))] +LL + #[coverage(off)] + | +LL - #[coverage(off(x, y, z))] +LL + #[coverage(on)] + | + +error[E0539]: malformed `rustc_abi` attribute input + --> $DIR/args-checked.rs:29:1 + | +LL | #[rustc_abi(debug = 5)] + | ^^^^^^^^^^^-----------^ + | | + | valid arguments are `assert_eq` or `debug` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_abi(debug = 5)] +LL + #[rustc_abi(assert_eq)] + | +LL - #[rustc_abi(debug = 5)] +LL + #[rustc_abi(debug)] + | + +error[E0539]: malformed `rustc_abi` attribute input + --> $DIR/args-checked.rs:31:1 + | +LL | #[rustc_abi(debug(x, y, z))] + | ^^^^^^^^^^^----------------^ + | | + | valid arguments are `assert_eq` or `debug` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_abi(debug(x, y, z))] +LL + #[rustc_abi(assert_eq)] + | +LL - #[rustc_abi(debug(x, y, z))] +LL + #[rustc_abi(debug)] + | + +error: `rustc_allow_const_fn_unstable` expects feature names + --> $DIR/args-checked.rs:47:33 + | +LL | #[rustc_allow_const_fn_unstable(x = 5)] + | ^^^^^ + +error: `rustc_allow_const_fn_unstable` expects feature names + --> $DIR/args-checked.rs:49:33 + | +LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] + | ^^^^^^^^^^ + +error[E0539]: malformed `used` attribute input + --> $DIR/args-checked.rs:53:1 + | +LL | #[used(always = 5)] + | ^^^^^^^----------^^ + | | + | valid arguments are `compiler` or `linker` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[used(always = 5)] +LL + #[used(compiler)] + | +LL - #[used(always = 5)] +LL + #[used(linker)] + | +LL - #[used(always = 5)] +LL + #[used] + | + +error[E0539]: malformed `used` attribute input + --> $DIR/args-checked.rs:55:1 + | +LL | #[used(always(x, y, z))] + | ^^^^^^^---------------^^ + | | + | valid arguments are `compiler` or `linker` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[used(always(x, y, z))] +LL + #[used(compiler)] + | +LL - #[used(always(x, y, z))] +LL + #[used(linker)] + | +LL - #[used(always(x, y, z))] +LL + #[used] + | + +error[E0565]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/args-checked.rs:59:1 + | +LL | #[rustc_must_implement_one_of(eq = 5, neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^ + | | + | expected a valid identifier here + | +help: must be of the form + | +LL - #[rustc_must_implement_one_of(eq = 5, neq)] +LL + #[rustc_must_implement_one_of(function1, function2, ...)] + | + +error[E0565]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/args-checked.rs:61:1 + | +LL | #[rustc_must_implement_one_of(eq(x, y, z), neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^ + | | + | expected a valid identifier here + | +help: must be of the form + | +LL - #[rustc_must_implement_one_of(eq(x, y, z), neq)] +LL + #[rustc_must_implement_one_of(function1, function2, ...)] + | + +error[E0565]: malformed `rustc_dump_layout` attribute input + --> $DIR/args-checked.rs:67:1 + | +LL | #[rustc_dump_layout(debug = 5)] + | ^^^^^^^^^^^^^^^^^^^^---------^^ + | | + | didn't expect a literal here + +error[E0565]: malformed `rustc_dump_layout` attribute input + --> $DIR/args-checked.rs:69:1 + | +LL | #[rustc_dump_layout(debug(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^--------------^^ + | | + | didn't expect a literal here + +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:37:1 + | +LL | #[macro_export(local_inner_macros = 5)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:40:1 + | +LL | #[macro_export(local_inner_macros(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error: aborting due to 23 previous errors + +Some errors have detailed explanations: E0539, E0565. +For more information about an error, try `rustc --explain E0539`. +Future incompatibility report: Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:37:1 + | +LL | #[macro_export(local_inner_macros = 5)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:40:1 + | +LL | #[macro_export(local_inner_macros(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/eii/unsafe_impl_err.rs b/tests/ui/eii/unsafe_impl_err.rs index a6d24c47ae213..c02f2143d73bd 100644 --- a/tests/ui/eii/unsafe_impl_err.rs +++ b/tests/ui/eii/unsafe_impl_err.rs @@ -5,6 +5,7 @@ #![feature(rustc_attrs)] #![feature(eii_internals)] +// Uses manual desugaring of EII internals. #[eii_declaration(bar, "unsafe")] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} @@ -18,6 +19,16 @@ fn other(x: u64) -> u64 { x } +// Uses the user-facing unsafe_eii wrapper. +#[unsafe_eii(baz)] +fn qux(x: u64) -> u64; + +#[baz] //~ ERROR `#[baz]` is unsafe to implement +fn another(x: u64) -> u64 { + x +} + fn main() { bar(0); + qux(0); } diff --git a/tests/ui/eii/unsafe_impl_err.stderr b/tests/ui/eii/unsafe_impl_err.stderr index eb917a65bb520..0eb3acda93991 100644 --- a/tests/ui/eii/unsafe_impl_err.stderr +++ b/tests/ui/eii/unsafe_impl_err.stderr @@ -1,5 +1,5 @@ error: `#[foo]` is unsafe to implement - --> $DIR/unsafe_impl_err.rs:16:1 + --> $DIR/unsafe_impl_err.rs:17:1 | LL | #[foo] | ^^^^^^ @@ -9,5 +9,16 @@ help: wrap the attribute in `unsafe(...)` LL | #[unsafe(foo)] | +++++++ + -error: aborting due to 1 previous error +error: `#[baz]` is unsafe to implement + --> $DIR/unsafe_impl_err.rs:26:1 + | +LL | #[baz] + | ^^^^^^ + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(baz)] + | +++++++ + + +error: aborting due to 2 previous errors diff --git a/tests/ui/eii/unsafe_impl_ok.rs b/tests/ui/eii/unsafe_impl_ok.rs index 1af6d63eb7cff..f7667afaf1956 100644 --- a/tests/ui/eii/unsafe_impl_ok.rs +++ b/tests/ui/eii/unsafe_impl_ok.rs @@ -1,12 +1,12 @@ //@ compile-flags: --crate-type rlib //@ check-pass -// Uses manual desugaring of EII internals: // Tests whether it's okay to implement an unsafe EII with an unsafe implementation. #![feature(extern_item_impls)] #![feature(decl_macro)] #![feature(rustc_attrs)] #![feature(eii_internals)] +// Uses manual desugaring of EII internals. #[eii_declaration(bar, "unsafe")] #[rustc_builtin_macro(eii_shared_macro)] macro foo() {} @@ -20,6 +20,16 @@ fn other(x: u64) -> u64 { x } +// Uses the user-facing unsafe_eii wrapper. +#[unsafe_eii(baz)] +fn qux(x: u64) -> u64; + +#[unsafe(baz)] +fn another(x: u64) -> u64 { + x +} + fn main() { bar(0); + qux(0); } diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.rs b/tests/ui/error-codes/E0152-duplicate-lang-items.rs index 4b243205dc481..17f235c615997 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.rs +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.rs @@ -12,9 +12,9 @@ extern crate core; use core::panic::PanicInfo; -#[lang = "panic_impl"] -fn panic_impl(info: &PanicInfo) -> ! { - //~^ ERROR: found duplicate lang item `panic_impl` +#[lang = "eh_personality"] +fn personality() { + //~^ ERROR: found duplicate lang item `eh_personality` //~| NOTE first defined in crate `std` loop {} } diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr index 55d5206b42ce9..3e6cbd2d1a560 100644 --- a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr +++ b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr @@ -1,7 +1,7 @@ -error[E0152]: found duplicate lang item `panic_impl` +error[E0152]: found duplicate lang item `eh_personality` --> $DIR/E0152-duplicate-lang-items.rs:16:1 | -LL | / fn panic_impl(info: &PanicInfo) -> ! { +LL | / fn personality() { LL | | LL | | LL | | loop {} diff --git a/tests/ui/macros/macro-comma-behavior.rs b/tests/ui/macros/macro-comma-behavior.rs index f00d4d3e85842..ea75fdd6842e1 100644 --- a/tests/ui/macros/macro-comma-behavior.rs +++ b/tests/ui/macros/macro-comma-behavior.rs @@ -10,7 +10,7 @@ #[cfg(core)] use core::fmt; #[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {} #[cfg(core)] #[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; -#[cfg(core)] #[lang = "panic_impl"] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } +#[cfg(core)] #[panic_handler] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } // (see documentation of the similarly-named test in run-pass) fn to_format_or_not_to_format() { diff --git a/tests/ui/panic-handler/panic-handler-duplicate.rs b/tests/ui/panic-handler/panic-handler-duplicate.rs index c0a7d6aa6d723..96a11157b5491 100644 --- a/tests/ui/panic-handler/panic-handler-duplicate.rs +++ b/tests/ui/panic-handler/panic-handler-duplicate.rs @@ -11,7 +11,7 @@ fn panic(info: &PanicInfo) -> ! { loop {} } -#[lang = "panic_impl"] +#[panic_handler] fn panic2(info: &PanicInfo) -> ! { //~ ERROR found duplicate lang item `panic_impl` loop {} } diff --git a/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs index 938f6bcb906b6..44137b85748fa 100644 --- a/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/tests/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -7,7 +7,7 @@ use core::panic::PanicInfo; -#[lang = "panic_impl"] +#[panic_handler] fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} diff --git a/tests/ui/rustc-env/def-path-hash-ice-157238.rs b/tests/ui/rustc-env/def-path-hash-ice-157238.rs new file mode 100644 index 0000000000000..42bf83001d5b7 --- /dev/null +++ b/tests/ui/rustc-env/def-path-hash-ice-157238.rs @@ -0,0 +1,9 @@ +//@ run-pass +// +// Ensure that `trace` level instrumentation in `def_path_hash` works, +// see #157238. +// +//@ dont-check-compiler-stdout +//@ dont-check-compiler-stderr +//@ rustc-env:RUSTC_LOG=trace +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 8c9702c407ea1..57a6119416a85 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -777,6 +777,10 @@ message_on_add = [ PR #{number} "{title}" fixes a regression and has been nominated for backport. {recipients}, what do you think about it? This topic will help T-compiler getting context about it. + +Tip: to approve or decline from this Zulip thread, use: +@_**triagebot** backport approve beta #{number} +@_**triagebot** backport decline beta #{number} """, """\ /poll Should #{number} be beta backported? @@ -802,6 +806,11 @@ message_on_add = [ """\ PR #{number} "{title}" fixes a regression and has been nominated for backport. {recipients}, what do you think about it? +This topic will help T-compiler getting context about it. + +Tip: to approve or decline from this Zulip thread, use: +@_**triagebot** backport approve stable #{number} +@_**triagebot** backport decline stable #{number} """, """\ /poll Approve stable backport of #{number}?