diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 5bbaeda18df3f..063fa12d38961 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -717,3 +717,100 @@ impl NoArgsAttributeParser for EiiForeignItemParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem; } + +pub(crate) struct PatchableFunctionEntryParser; + +impl SingleAttributeParser for PatchableFunctionEntryParser { + const PATH: &[Symbol] = &[sym::patchable_function_entry]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(meta_item_list) = args.list() else { + cx.expected_list(cx.attr_span, args); + return None; + }; + + let mut prefix = None; + let mut entry = None; + + if meta_item_list.len() == 0 { + cx.expected_list(meta_item_list.span, args); + return None; + } + + let mut errored = false; + + for item in meta_item_list.mixed() { + let Some(meta_item) = item.meta_item() else { + errored = true; + cx.expected_name_value(item.span(), None); + continue; + }; + + let Some(name_value_lit) = meta_item.args().name_value() else { + errored = true; + cx.expected_name_value(item.span(), None); + continue; + }; + + let attrib_to_write = match meta_item.ident().map(|ident| ident.name) { + Some(sym::prefix_nops) => { + // Duplicate prefixes are not allowed + if prefix.is_some() { + errored = true; + cx.duplicate_key(meta_item.path().span(), sym::prefix_nops); + continue; + } + &mut prefix + } + Some(sym::entry_nops) => { + // Duplicate entries are not allowed + if entry.is_some() { + errored = true; + cx.duplicate_key(meta_item.path().span(), sym::entry_nops); + continue; + } + &mut entry + } + _ => { + errored = true; + cx.expected_specific_argument( + meta_item.path().span(), + &[sym::prefix_nops, sym::entry_nops], + ); + continue; + } + }; + + let rustc_ast::LitKind::Int(val, _) = name_value_lit.value_as_lit().kind else { + errored = true; + cx.expected_integer_literal(name_value_lit.value_span); + continue; + }; + + let Ok(val) = val.get().try_into() else { + errored = true; + cx.expected_integer_literal_in_range( + name_value_lit.value_span, + u8::MIN as isize, + u8::MAX as isize, + ); + continue; + }; + + *attrib_to_write = Some(val); + } + + if errored { + None + } else { + Some(AttributeKind::PatchableFunctionEntry { + prefix: prefix.unwrap_or(0), + entry: entry.unwrap_or(0), + }) + } + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 7f25641b948e2..ec7cdd3624dc3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -91,3 +91,25 @@ impl SingleAttributeParser for ShouldPanicParser { }) } } + +pub(crate) struct RustcVarianceParser; + +impl NoArgsAttributeParser for RustcVarianceParser { + const PATH: &[Symbol] = &[sym::rustc_variance]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance; +} + +pub(crate) struct RustcVarianceOfOpaquesParser; + +impl NoArgsAttributeParser for RustcVarianceOfOpaquesParser { + const PATH: &[Symbol] = &[sym::rustc_variance_of_opaques]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVarianceOfOpaques; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6aae2b90a5045..366998ff42045 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -23,8 +23,8 @@ use crate::attributes::cfi_encoding::CfiEncodingParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, - RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser, - ThreadLocalParser, TrackCallerParser, UsedParser, + PatchableFunctionEntryParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, + TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ @@ -85,7 +85,9 @@ use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; -use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser}; +use crate::attributes::test_attrs::{ + IgnoreParser, RustcVarianceOfOpaquesParser, RustcVarianceParser, ShouldPanicParser, +}; use crate::attributes::traits::{ AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser, @@ -223,6 +225,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, @@ -300,6 +303,8 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, + Single>, Single>, Single>, Single>, @@ -503,6 +508,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral) } + pub(crate) fn expected_integer_literal_in_range( + &self, + span: Span, + lower_bound: isize, + upper_bound: isize, + ) -> ErrorGuaranteed { + self.emit_parse_error( + span, + AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound }, + ) + } + pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed { let span = match args { ArgParser::NoArgs => span, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 85e7891b1e64b..f9748542beb94 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -525,6 +525,10 @@ pub(crate) enum AttributeParseErrorReason<'a> { byte_string: Option, }, ExpectedIntegerLiteral, + ExpectedIntegerLiteralInRange { + lower_bound: isize, + upper_bound: isize, + }, ExpectedAtLeastOneArgument, ExpectedSingleArgument, ExpectedList, @@ -596,6 +600,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { AttributeParseErrorReason::ExpectedIntegerLiteral => { diag.span_label(self.span, "expected an integer literal here"); } + AttributeParseErrorReason::ExpectedIntegerLiteralInRange { + lower_bound, + upper_bound, + } => { + diag.span_label( + self.span, + format!( + "expected an integer literal in the range of {lower_bound}..={upper_bound}" + ), + ); + } AttributeParseErrorReason::ExpectedSingleArgument => { diag.span_label(self.span, "expected a single argument here"); diag.code(E0805); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index a78c6e0a4e7ac..ab9a11305baa3 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1506,7 +1506,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } // FIXME implement variadics in cranelift - sym::va_copy | sym::va_arg | sym::va_end => { + sym::va_arg | sym::va_end => { fx.tcx.dcx().span_fatal( source_info.span, "Defining variadic functions is not yet supported by Cranelift", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 36ea76cbc51a0..553e4d3d2fe09 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -391,9 +391,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc sym::breakpoint => { unimplemented!(); } - sym::va_copy => { - unimplemented!(); - } sym::va_arg => { unimplemented!(); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4328b15c73f30..2760683dad9d1 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -221,6 +221,12 @@ pub(crate) unsafe fn create_module<'ll>( target_data_layout = target_data_layout.replace("-m:e", ""); } } + if llvm_version < (23, 0, 0) { + if sess.target.arch == Arch::S390x { + // LLVM 23 updated the s390x layout to specify the stack alignment: https://github.com/llvm/llvm-project/pull/176041 + target_data_layout = target_data_layout.replace("-S64", ""); + } + } // Ensure the data-layout values hardcoded remain the defaults. { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 20eac4cf92c20..a712b7b4138c3 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -269,14 +269,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { return Ok(()); } sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]), - sym::va_copy => { - let dest = args[0].immediate(); - self.call_intrinsic( - "llvm.va_copy", - &[self.val_ty(dest)], - &[dest, args[1].immediate()], - ) - } sym::va_arg => { match result.layout.backend_repr { BackendRepr::Scalar(scalar) => { diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 4875f309cca5f..a49f411a7df62 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -48,8 +48,6 @@ codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$err codegen_ssa_error_writing_def_file = error writing .DEF file: {$error} -codegen_ssa_expected_name_value_pair = expected name value pair - codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error} @@ -90,9 +88,6 @@ codegen_ssa_incorrect_cgu_reuse_type = codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. -codegen_ssa_invalid_literal_value = invalid literal value - .label = value must be an integer between `0` and `255` - codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}` codegen_ssa_invalid_monomorphization_basic_integer_or_ptr_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer or pointer type, found `{$ty}` @@ -225,9 +220,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't -codegen_ssa_out_of_range_integer = integer value out of range - .label = value must be between `0` and `255` - codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} .note = {$output} @@ -357,9 +349,6 @@ codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error} codegen_ssa_unable_to_write_debugger_visualizer = unable to write debugger visualizer file `{$path}`: {$error} -codegen_ssa_unexpected_parameter_name = unexpected parameter name - .label = expected `{$prefix_nops}` or `{$entry_nops}` - codegen_ssa_unknown_archive_kind = don't know how to build archive of type: {$kind} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e35d884b6711c..d55e134109d66 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -47,59 +47,6 @@ fn try_fn_sig<'tcx>( } } -// FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr -fn parse_patchable_function_entry( - tcx: TyCtxt<'_>, - attr: &Attribute, -) -> Option { - attr.meta_item_list().and_then(|l| { - let mut prefix = None; - let mut entry = None; - for item in l { - let Some(meta_item) = item.meta_item() else { - tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); - continue; - }; - - let Some(name_value_lit) = meta_item.name_value_literal() else { - tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); - continue; - }; - - let attrib_to_write = match meta_item.name() { - Some(sym::prefix_nops) => &mut prefix, - Some(sym::entry_nops) => &mut entry, - _ => { - tcx.dcx().emit_err(errors::UnexpectedParameterName { - span: item.span(), - prefix_nops: sym::prefix_nops, - entry_nops: sym::entry_nops, - }); - continue; - } - }; - - let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { - tcx.dcx().emit_err(errors::InvalidLiteralValue { span: name_value_lit.span }); - continue; - }; - - let Ok(val) = val.get().try_into() else { - tcx.dcx().emit_err(errors::OutOfRangeInteger { span: name_value_lit.span }); - continue; - }; - - *attrib_to_write = Some(val); - } - - if let (None, None) = (prefix, entry) { - tcx.dcx().span_err(attr.span(), "must specify at least one parameter"); - } - - Some(PatchableFunctionEntry::from_prefix_and_entry(prefix.unwrap_or(0), entry.unwrap_or(0))) - }) -} - /// Spans that are collected when processing built-in attributes, /// that are useful for emitting diagnostics later. #[derive(Default)] @@ -121,250 +68,235 @@ fn process_builtin_attrs( let mut interesting_spans = InterestingAttributeDiagnosticSpans::default(); let rust_target_features = tcx.rust_target_features(LOCAL_CRATE); - for attr in attrs.iter() { - if let hir::Attribute::Parsed(p) = attr { - match p { - AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, - AttributeKind::ExportName { name, .. } => { - codegen_fn_attrs.symbol_name = Some(*name) + let parsed_attrs = attrs + .iter() + .filter_map(|attr| if let hir::Attribute::Parsed(attr) = attr { Some(attr) } else { None }); + for attr in parsed_attrs { + match attr { + AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, + AttributeKind::ExportName { name, .. } => codegen_fn_attrs.symbol_name = Some(*name), + AttributeKind::Inline(inline, span) => { + codegen_fn_attrs.inline = *inline; + interesting_spans.inline = Some(*span); + } + AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, + AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + AttributeKind::LinkName { name, .. } => { + // FIXME Remove check for foreign functions once #[link_name] on non-foreign + // functions is a hard error + if tcx.is_foreign_item(did) { + codegen_fn_attrs.symbol_name = Some(*name); } - AttributeKind::Inline(inline, span) => { - codegen_fn_attrs.inline = *inline; - interesting_spans.inline = Some(*span); + } + AttributeKind::LinkOrdinal { ordinal, span } => { + codegen_fn_attrs.link_ordinal = Some(*ordinal); + interesting_spans.link_ordinal = Some(*span); + } + AttributeKind::LinkSection { name, .. } => codegen_fn_attrs.link_section = Some(*name), + AttributeKind::NoMangle(attr_span) => { + interesting_spans.no_mangle = Some(*attr_span); + if tcx.opt_item_name(did.to_def_id()).is_some() { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + } else { + tcx.dcx() + .span_delayed_bug(*attr_span, "no_mangle should be on a named function"); } - AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), - AttributeKind::LinkName { name, .. } => { - // FIXME Remove check for foreign functions once #[link_name] on non-foreign - // functions is a hard error - if tcx.is_foreign_item(did) { - codegen_fn_attrs.symbol_name = Some(*name); + } + AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize, + AttributeKind::TargetFeature { features, attr_span, was_forced } => { + let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { + tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn"); + continue; + }; + let safe_target_features = + matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures); + codegen_fn_attrs.safe_target_features = safe_target_features; + if safe_target_features && !was_forced { + if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { + // The `#[target_feature]` attribute is allowed on + // WebAssembly targets on all functions. Prior to stabilizing + // the `target_feature_11` feature, `#[target_feature]` was + // only permitted on unsafe functions because on most targets + // execution of instructions that are not supported is + // considered undefined behavior. For WebAssembly which is a + // 100% safe target at execution time it's not possible to + // execute undefined instructions, and even if a future + // feature was added in some form for this it would be a + // deterministic trap. There is no undefined behavior when + // executing WebAssembly so `#[target_feature]` is allowed + // on safe functions (but again, only for WebAssembly) + // + // Note that this is also allowed if `actually_rustdoc` so + // if a target is documenting some wasm-specific code then + // it's not spuriously denied. + // + // Now that `#[target_feature]` is permitted on safe functions, + // this exception must still exist for allowing the attribute on + // `main`, `start`, and other functions that are not usually + // allowed. + } else { + check_target_feature_trait_unsafe(tcx, did, *attr_span); } } - AttributeKind::LinkOrdinal { ordinal, span } => { - codegen_fn_attrs.link_ordinal = Some(*ordinal); - interesting_spans.link_ordinal = Some(*span); + from_target_feature_attr( + tcx, + did, + features, + *was_forced, + rust_target_features, + &mut codegen_fn_attrs.target_features, + ); + } + AttributeKind::TrackCaller(attr_span) => { + let is_closure = tcx.is_closure_like(did.to_def_id()); + + if !is_closure + && let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span) + && fn_sig.skip_binder().abi() != ExternAbi::Rust + { + tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span }); } - AttributeKind::LinkSection { name, .. } => { - codegen_fn_attrs.link_section = Some(*name) + if is_closure + && !tcx.features().closure_track_caller() + && !attr_span.allows_unstable(sym::closure_track_caller) + { + feature_err( + &tcx.sess, + sym::closure_track_caller, + *attr_span, + "`#[track_caller]` on closures is currently unstable", + ) + .emit(); } - AttributeKind::NoMangle(attr_span) => { - interesting_spans.no_mangle = Some(*attr_span); - if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER + } + AttributeKind::Used { used_by, .. } => match used_by { + UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER, + UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER, + UsedBy::Default => { + let used_form = if tcx.sess.target.os == Os::Illumos { + // illumos' `ld` doesn't support a section header that would represent + // `#[used(linker)]`, see + // https://github.com/rust-lang/rust/issues/146169. For that target, + // downgrade as if `#[used(compiler)]` was requested and hope for the + // best. + CodegenFnAttrFlags::USED_COMPILER } else { - tcx.dcx().span_delayed_bug( - *attr_span, - "no_mangle should be on a named function", - ); - } - } - AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize, - AttributeKind::TargetFeature { features, attr_span, was_forced } => { - let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { - tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn"); - continue; + CodegenFnAttrFlags::USED_LINKER }; - let safe_target_features = - matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures); - codegen_fn_attrs.safe_target_features = safe_target_features; - if safe_target_features && !was_forced { - if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { - // The `#[target_feature]` attribute is allowed on - // WebAssembly targets on all functions. Prior to stabilizing - // the `target_feature_11` feature, `#[target_feature]` was - // only permitted on unsafe functions because on most targets - // execution of instructions that are not supported is - // considered undefined behavior. For WebAssembly which is a - // 100% safe target at execution time it's not possible to - // execute undefined instructions, and even if a future - // feature was added in some form for this it would be a - // deterministic trap. There is no undefined behavior when - // executing WebAssembly so `#[target_feature]` is allowed - // on safe functions (but again, only for WebAssembly) - // - // Note that this is also allowed if `actually_rustdoc` so - // if a target is documenting some wasm-specific code then - // it's not spuriously denied. - // - // Now that `#[target_feature]` is permitted on safe functions, - // this exception must still exist for allowing the attribute on - // `main`, `start`, and other functions that are not usually - // allowed. - } else { - check_target_feature_trait_unsafe(tcx, did, *attr_span); - } - } - from_target_feature_attr( - tcx, - did, - features, - *was_forced, - rust_target_features, - &mut codegen_fn_attrs.target_features, - ); + codegen_fn_attrs.flags |= used_form; } - AttributeKind::TrackCaller(attr_span) => { - let is_closure = tcx.is_closure_like(did.to_def_id()); + }, + AttributeKind::FfiConst(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST, + AttributeKind::FfiPure(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE, + AttributeKind::StdInternalSymbol(_) => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL + } + AttributeKind::Linkage(linkage, span) => { + let linkage = Some(*linkage); - if !is_closure - && let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span) - && fn_sig.skip_binder().abi() != ExternAbi::Rust - { - tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span }); - } - if is_closure - && !tcx.features().closure_track_caller() - && !attr_span.allows_unstable(sym::closure_track_caller) - { - feature_err( - &tcx.sess, - sym::closure_track_caller, - *attr_span, - "`#[track_caller]` on closures is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER - } - AttributeKind::Used { used_by, .. } => match used_by { - UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER, - UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER, - UsedBy::Default => { - let used_form = if tcx.sess.target.os == Os::Illumos { - // illumos' `ld` doesn't support a section header that would represent - // `#[used(linker)]`, see - // https://github.com/rust-lang/rust/issues/146169. For that target, - // downgrade as if `#[used(compiler)]` was requested and hope for the - // best. - CodegenFnAttrFlags::USED_COMPILER - } else { - CodegenFnAttrFlags::USED_LINKER - }; - codegen_fn_attrs.flags |= used_form; - } - }, - AttributeKind::FfiConst(_) => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST - } - AttributeKind::FfiPure(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE, - AttributeKind::StdInternalSymbol(_) => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL - } - AttributeKind::Linkage(linkage, span) => { - let linkage = Some(*linkage); - - if tcx.is_foreign_item(did) { - codegen_fn_attrs.import_linkage = linkage; - - if tcx.is_mutable_static(did.into()) { - let mut diag = tcx.dcx().struct_span_err( - *span, - "extern mutable statics are not allowed with `#[linkage]`", - ); - diag.note( - "marking the extern static mutable would allow changing which \ - symbol the static references rather than make the target of the \ - symbol mutable", - ); - diag.emit(); - } - } else { - codegen_fn_attrs.linkage = linkage; + if tcx.is_foreign_item(did) { + codegen_fn_attrs.import_linkage = linkage; + + if tcx.is_mutable_static(did.into()) { + let mut diag = tcx.dcx().struct_span_err( + *span, + "extern mutable statics are not allowed with `#[linkage]`", + ); + diag.note( + "marking the extern static mutable would allow changing which \ + symbol the static references rather than make the target of the \ + symbol mutable", + ); + diag.emit(); } + } else { + codegen_fn_attrs.linkage = linkage; } - AttributeKind::Sanitize { span, .. } => { - interesting_spans.sanitize = Some(*span); - } - AttributeKind::ObjcClass { classname, .. } => { - codegen_fn_attrs.objc_class = Some(*classname); - } - AttributeKind::ObjcSelector { methname, .. } => { - codegen_fn_attrs.objc_selector = Some(*methname); - } - AttributeKind::EiiForeignItem => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; - } - AttributeKind::EiiImpls(impls) => { - for i in impls { - let foreign_item = match i.resolution { - EiiImplResolution::Macro(def_id) => { - let Some(extern_item) = find_attr!( - tcx.get_all_attrs(def_id), - AttributeKind::EiiDeclaration(target) => target.foreign_item - ) else { - tcx.dcx().span_delayed_bug( - i.span, - "resolved to something that's not an EII", - ); - continue; - }; - extern_item - } - EiiImplResolution::Known(decl) => decl.foreign_item, - EiiImplResolution::Error(_eg) => continue, - }; - - // this is to prevent a bug where a single crate defines both the default and explicit implementation - // for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure - // what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent. - // However, the fact that the default one of has weak linkage isn't considered and you sometimes get that - // the default implementation is used while an explicit implementation is given. - if - // if this is a default impl - i.is_default - // iterate over all implementations *in the current crate* - // (this is ok since we generate codegen fn attrs in the local crate) - // if any of them is *not default* then don't emit the alias. - && tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) - { - continue; + } + AttributeKind::Sanitize { span, .. } => { + interesting_spans.sanitize = Some(*span); + } + AttributeKind::ObjcClass { classname, .. } => { + codegen_fn_attrs.objc_class = Some(*classname); + } + AttributeKind::ObjcSelector { methname, .. } => { + codegen_fn_attrs.objc_selector = Some(*methname); + } + AttributeKind::EiiForeignItem => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; + } + AttributeKind::EiiImpls(impls) => { + for i in impls { + let foreign_item = match i.resolution { + EiiImplResolution::Macro(def_id) => { + let Some(extern_item) = find_attr!( + tcx.get_all_attrs(def_id), + AttributeKind::EiiDeclaration(target) => target.foreign_item + ) else { + tcx.dcx().span_delayed_bug( + i.span, + "resolved to something that's not an EII", + ); + continue; + }; + extern_item } + EiiImplResolution::Known(decl) => decl.foreign_item, + EiiImplResolution::Error(_eg) => continue, + }; - codegen_fn_attrs.foreign_item_symbol_aliases.push(( - foreign_item, - if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, - Visibility::Default, - )); - codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; + // this is to prevent a bug where a single crate defines both the default and explicit implementation + // for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure + // what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent. + // However, the fact that the default one of has weak linkage isn't considered and you sometimes get that + // the default implementation is used while an explicit implementation is given. + if + // if this is a default impl + i.is_default + // iterate over all implementations *in the current crate* + // (this is ok since we generate codegen fn attrs in the local crate) + // if any of them is *not default* then don't emit the alias. + && tcx.externally_implementable_items(LOCAL_CRATE).get(&foreign_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) + { + continue; } + + codegen_fn_attrs.foreign_item_symbol_aliases.push(( + foreign_item, + if i.is_default { Linkage::LinkOnceAny } else { Linkage::External }, + Visibility::Default, + )); + codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; } - AttributeKind::ThreadLocal => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL - } - AttributeKind::InstructionSet(instruction_set) => { - codegen_fn_attrs.instruction_set = Some(*instruction_set) - } - AttributeKind::RustcAllocator => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR - } - AttributeKind::RustcDeallocator => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR - } - AttributeKind::RustcReallocator => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR - } - AttributeKind::RustcAllocatorZeroed => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED - } - AttributeKind::RustcNounwind => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND - } - AttributeKind::RustcOffloadKernel => { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL - } - _ => {} } - } - - let Some(name) = attr.name() else { - continue; - }; - - match name { - sym::patchable_function_entry => { + AttributeKind::ThreadLocal => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL + } + AttributeKind::InstructionSet(instruction_set) => { + codegen_fn_attrs.instruction_set = Some(*instruction_set) + } + AttributeKind::RustcAllocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR + } + AttributeKind::RustcDeallocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR + } + AttributeKind::RustcReallocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR + } + AttributeKind::RustcAllocatorZeroed => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED + } + AttributeKind::RustcNounwind => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND + } + AttributeKind::RustcOffloadKernel => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL + } + AttributeKind::PatchableFunctionEntry { prefix, entry } => { codegen_fn_attrs.patchable_function_entry = - parse_patchable_function_entry(tcx, attr); + Some(PatchableFunctionEntry::from_prefix_and_entry(*prefix, *entry)); } _ => {} } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 39727685aec1a..6a97de4c2b132 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -136,39 +136,6 @@ pub(crate) struct RequiresRustAbi { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_expected_name_value_pair)] -pub(crate) struct ExpectedNameValuePair { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_unexpected_parameter_name)] -pub(crate) struct UnexpectedParameterName { - #[primary_span] - #[label] - pub span: Span, - pub prefix_nops: Symbol, - pub entry_nops: Symbol, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_literal_value)] -pub(crate) struct InvalidLiteralValue { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_out_of_range_integer)] -pub(crate) struct OutOfRangeInteger { - #[primary_span] - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_copy_path_buf)] pub(crate) struct CopyPathBuf { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8d2baae703b8f..f32e69f61d082 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -879,6 +879,9 @@ pub enum AttributeKind { /// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint). PassByValue(Span), + /// Represents `#[patchable_function_entry]` + PatchableFunctionEntry { prefix: u8, entry: u8 }, + /// Represents `#[path]` Path(Symbol, Span), @@ -1007,6 +1010,12 @@ pub enum AttributeKind { /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`. RustcSimdMonomorphizeLaneLimit(Limit), + /// Represents `#[rustc_variance]` + RustcVariance, + + /// Represents `#[rustc_variance_of_opaques]` + RustcVarianceOfOpaques, + /// Represents `#[sanitize]` /// /// the on set and off set are distjoint since there's a third option: unset. diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index fd764ad458b14..712775eef6de1 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -88,6 +88,7 @@ impl AttributeKind { Optimize(..) => No, ParenSugar(..) => No, PassByValue(..) => Yes, + PatchableFunctionEntry { .. } => Yes, Path(..) => No, PatternComplexityLimit { .. } => No, PinV2(..) => Yes, @@ -129,6 +130,8 @@ impl AttributeKind { RustcScalableVector { .. } => Yes, RustcShouldNotBeCalledOnConstItems(..) => Yes, RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate + RustcVariance => No, + RustcVarianceOfOpaques => No, Sanitize { .. } => No, ShouldPanic { .. } => No, SkipDuringMethodDispatch { .. } => No, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index 806f5c4d3ed91..c2ad644688fce 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -171,7 +171,7 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, (), ErrorGuaranteed); -print_disp!(u16, u128, usize, bool, NonZero, Limit); +print_disp!(u8, u16, u128, usize, bool, NonZero, Limit); print_debug!( Symbol, Ident, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d3d167f6e2544..98f9548058f45 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -216,6 +216,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::type_name | sym::type_of | sym::ub_checks + | sym::va_copy | sym::variant_count | sym::vtable_for | sym::wrapping_add @@ -629,14 +630,13 @@ pub(crate) fn check_intrinsic_type( ) } - sym::va_start | sym::va_end => { - (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit) - } - sym::va_copy => { let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not); - let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); - (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit) + (0, 0, vec![va_list_ref_ty], va_list_ty) + } + + sym::va_start | sym::va_end => { + (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit) } sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)), diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index 31f0adf720d79..e625d9dfe3b5f 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -1,8 +1,9 @@ use std::fmt::Write; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; +use rustc_hir::find_attr; use rustc_middle::ty::{GenericArgs, TyCtxt}; -use rustc_span::sym; fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { let variances = tcx.variances_of(def_id); @@ -25,7 +26,7 @@ fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { pub(crate) fn variances(tcx: TyCtxt<'_>) { let crate_items = tcx.hir_crate_items(()); - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + if find_attr!(tcx.get_all_attrs(CRATE_DEF_ID), AttributeKind::RustcVarianceOfOpaques) { for id in crate_items.opaques() { tcx.dcx().emit_err(crate::errors::VariancesOf { span: tcx.def_span(id), @@ -35,7 +36,7 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) { } for id in crate_items.free_items() { - if !tcx.has_attr(id.owner_id, sym::rustc_variance) { + if !find_attr!(tcx.get_all_attrs(id.owner_id), AttributeKind::RustcVariance) { continue; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4266731cf0a22..659e5535ca50a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -274,6 +274,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcScalableVector { .. } | AttributeKind::RustcSimdMonomorphizeLaneLimit(..) | AttributeKind::RustcShouldNotBeCalledOnConstItems(..) + | AttributeKind::RustcVariance + | AttributeKind::RustcVarianceOfOpaques | AttributeKind::ExportStable | AttributeKind::FfiConst(..) | AttributeKind::UnstableFeatureBound(..) @@ -323,6 +325,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcReallocator | AttributeKind::RustcNounwind | AttributeKind::RustcOffloadKernel + | AttributeKind::PatchableFunctionEntry { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -348,7 +351,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::deny | sym::forbid // need to be fixed - | sym::patchable_function_entry // FIXME(patchable_function_entry) | sym::deprecated_safe // FIXME(deprecated_safe) // internal | sym::prelude_import @@ -378,8 +380,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_capture_analysis | sym::rustc_regions | sym::rustc_strict_coherence - | sym::rustc_variance - | sym::rustc_variance_of_opaques | sym::rustc_hidden_type_of_opaques | sym::rustc_mir | sym::rustc_effective_visibility diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs index a64e867b9a1cb..8859e0d650a2b 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), + data_layout: "E-S64-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), arch: Arch::S390x, options: base, } diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index 69c25d72432c5..21e705ebbec5d 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), + data_layout: "E-S64-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), arch: Arch::S390x, options: base, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 00d06779e652e..6872d038fb7f0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1442,6 +1442,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.can_eq(param_env, goal.trait_ref, trait_assumption.trait_ref) } + fn can_match_host_effect( + &self, + param_env: ty::ParamEnv<'tcx>, + goal: ty::HostEffectPredicate<'tcx>, + assumption: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, + ) -> bool { + let assumption = self.instantiate_binder_with_fresh_vars( + DUMMY_SP, + infer::BoundRegionConversionTime::HigherRankedType, + assumption, + ); + + assumption.constness.satisfies(goal.constness) + && self.can_eq(param_env, goal.trait_ref, assumption.trait_ref) + } + + fn as_host_effect_clause( + predicate: ty::Predicate<'tcx>, + ) -> Option>> { + predicate.as_clause().and_then(|clause| match clause.kind().skip_binder() { + ty::ClauseKind::HostEffect(pred) => Some(clause.kind().rebind(pred)), + _ => None, + }) + } + fn can_match_projection( &self, param_env: ty::ParamEnv<'tcx>, @@ -1484,6 +1509,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .filter_map(|implied| implied.as_trait_clause()) .any(|implied| self.can_match_trait(param_env, error, implied)) }) + } else if let Some(error) = Self::as_host_effect_clause(error.predicate) { + self.enter_forall(error, |error| { + elaborate(self.tcx, std::iter::once(cond.predicate)) + .filter_map(Self::as_host_effect_clause) + .any(|implied| self.can_match_host_effect(param_env, error, implied)) + }) } else if let Some(error) = error.predicate.as_projection_clause() { self.enter_forall(error, |error| { elaborate(self.tcx, std::iter::once(cond.predicate)) diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index d5166baf0c7ca..d0f155316a109 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -5,7 +5,7 @@ #[cfg(not(target_arch = "xtensa"))] use crate::ffi::c_void; use crate::fmt; -use crate::intrinsics::{va_arg, va_copy}; +use crate::intrinsics::{va_arg, va_copy, va_end}; use crate::marker::PhantomCovariantLifetime; // There are currently three flavors of how a C `va_list` is implemented for @@ -34,6 +34,10 @@ use crate::marker::PhantomCovariantLifetime; // // The Clang `BuiltinVaListKind` enumerates the `va_list` variations that Clang supports, // and we mirror these here. +// +// For all current LLVM targets, `va_copy` lowers to `memcpy`. Hence the inner structs below all +// derive `Copy`. However, in the future we might want to support a target where `va_copy` +// allocates, or otherwise violates the requirements of `Copy`. Therefore `VaList` is only `Clone`. crate::cfg_select! { all( target_arch = "aarch64", @@ -45,10 +49,12 @@ crate::cfg_select! { /// /// See the [AArch64 Procedure Call Standard] for more details. /// + /// `va_copy` is `memcpy`: + /// /// [AArch64 Procedure Call Standard]: /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf #[repr(C)] - #[derive(Debug)] + #[derive(Debug, Clone, Copy)] struct VaListInner { stack: *const c_void, gr_top: *const c_void, @@ -62,11 +68,13 @@ crate::cfg_select! { /// /// See the [LLVM source] and [GCC header] for more details. /// + /// `va_copy` is `memcpy`: + /// /// [LLVM source]: /// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/PowerPC/PPCISelLowering.cpp#L4089-L4111 /// [GCC header]: https://web.mit.edu/darwin/src/modules/gcc/gcc/ginclude/va-ppc.h #[repr(C)] - #[derive(Debug)] + #[derive(Debug, Clone, Copy)] #[rustc_pass_indirectly_in_non_rustic_abis] struct VaListInner { gpr: u8, @@ -81,10 +89,12 @@ crate::cfg_select! { /// /// See the [S/390x ELF Application Binary Interface Supplement] for more details. /// + /// `va_copy` is `memcpy`: + /// /// [S/390x ELF Application Binary Interface Supplement]: /// https://docs.google.com/gview?embedded=true&url=https://github.com/IBM/s390x-abi/releases/download/v1.7/lzsabi_s390x.pdf #[repr(C)] - #[derive(Debug)] + #[derive(Debug, Clone, Copy)] #[rustc_pass_indirectly_in_non_rustic_abis] struct VaListInner { gpr: i64, @@ -98,10 +108,13 @@ crate::cfg_select! { /// /// See the [System V AMD64 ABI] for more details. /// + /// `va_copy` is `memcpy`: + /// (github won't render that file, look for `SDValue LowerVACOPY`) + /// /// [System V AMD64 ABI]: /// https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf #[repr(C)] - #[derive(Debug)] + #[derive(Debug, Clone, Copy)] #[rustc_pass_indirectly_in_non_rustic_abis] struct VaListInner { gp_offset: i32, @@ -115,10 +128,12 @@ crate::cfg_select! { /// /// See the [LLVM source] for more details. /// + /// `va_copy` is `memcpy`: + /// /// [LLVM source]: /// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp#L1211-L1215 #[repr(C)] - #[derive(Debug)] + #[derive(Debug, Clone, Copy)] #[rustc_pass_indirectly_in_non_rustic_abis] struct VaListInner { stk: *const i32, @@ -132,10 +147,12 @@ crate::cfg_select! { /// /// See the [LLVM source] for more details. On bare metal Hexagon uses an opaque pointer. /// + /// `va_copy` is `memcpy`: + /// /// [LLVM source]: /// https://github.com/llvm/llvm-project/blob/0cdc1b6dd4a870fc41d4b15ad97e0001882aba58/clang/lib/CodeGen/Targets/Hexagon.cpp#L407-L417 #[repr(C)] - #[derive(Debug)] + #[derive(Debug, Clone, Copy)] #[rustc_pass_indirectly_in_non_rustic_abis] struct VaListInner { __current_saved_reg_area_pointer: *const c_void, @@ -156,8 +173,10 @@ crate::cfg_select! { // That pointer is probably just the next variadic argument on the caller's stack. _ => { /// Basic implementation of a `va_list`. + /// + /// `va_copy` is `memcpy`: #[repr(transparent)] - #[derive(Debug)] + #[derive(Debug, Clone, Copy)] struct VaListInner { ptr: *const c_void, } @@ -179,6 +198,31 @@ impl fmt::Debug for VaList<'_> { } } +impl VaList<'_> { + // Helper used in the implementation of the `va_copy` intrinsic. + pub(crate) fn duplicate(&self) -> Self { + Self { inner: self.inner.clone(), _marker: self._marker } + } +} + +impl Clone for VaList<'_> { + #[inline] + fn clone(&self) -> Self { + // We only implement Clone and not Copy because some future target might not be able to + // implement Copy (e.g. because it allocates). For the same reason we use an intrinsic + // to do the copying: the fact that on all current targets, this is just `memcpy`, is an implementation + // detail. The intrinsic lets Miri catch UB from code incorrectly relying on that implementation detail. + va_copy(self) + } +} + +impl<'f> Drop for VaList<'f> { + fn drop(&mut self) { + // SAFETY: this variable argument list is being dropped, so won't be read from again. + unsafe { va_end(self) } + } +} + mod sealed { pub trait Sealed {} @@ -253,26 +297,6 @@ impl<'f> VaList<'f> { } } -impl<'f> Clone for VaList<'f> { - #[inline] - fn clone(&self) -> Self { - let mut dest = crate::mem::MaybeUninit::uninit(); - // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal. - unsafe { - va_copy(dest.as_mut_ptr(), self); - dest.assume_init() - } - } -} - -impl<'f> Drop for VaList<'f> { - fn drop(&mut self) { - // Rust requires that not calling `va_end` on a `va_list` does not cause undefined behaviour - // (as it is safe to leak values). As `va_end` is a no-op on all current LLVM targets, this - // destructor is empty. - } -} - // Checks (via an assert in `compiler/rustc_ty_utils/src/abi.rs`) that the C ABI for the current // target correctly implements `rustc_pass_indirectly_in_non_rustic_abis`. const _: () = { diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 8d112b4c5d187..b134c0ba4c8bb 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3451,19 +3451,6 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize ) } -/// Copies the current location of arglist `src` to the arglist `dst`. -/// -/// # Safety -/// -/// You must check the following invariants before you call this function: -/// -/// - `dest` must be non-null and point to valid, writable memory. -/// - `dest` must not alias `src`. -/// -#[rustc_intrinsic] -#[rustc_nounwind] -pub unsafe fn va_copy<'f>(dest: *mut VaList<'f>, src: &VaList<'f>); - /// Loads an argument of type `T` from the `va_list` `ap` and increment the /// argument `ap` points to. /// @@ -3482,7 +3469,28 @@ pub unsafe fn va_copy<'f>(dest: *mut VaList<'f>, src: &VaList<'f>); #[rustc_nounwind] pub unsafe fn va_arg(ap: &mut VaList<'_>) -> T; -/// Destroy the arglist `ap` after initialization with `va_start` or `va_copy`. +/// Duplicates a variable argument list. The returned list is initially at the same position as +/// the one in `src`, but can be advanced independently. +/// +/// Codegen backends should not have custom behavior for this intrinsic, they should always use +/// this fallback implementation. This intrinsic *does not* map to the LLVM `va_copy` intrinsic. +/// +/// This intrinsic exists only as a hook for Miri and constant evaluation, and is used to detect UB +/// when a variable argument list is used incorrectly. +#[rustc_intrinsic] +#[rustc_nounwind] +pub fn va_copy<'f>(src: &VaList<'f>) -> VaList<'f> { + src.duplicate() +} + +/// Destroy the variable argument list `ap` after initialization with `va_start` (part of the +/// desugaring of `...`) or `va_copy`. +/// +/// Code generation backends should not provide a custom implementation for this intrinsic. This +/// intrinsic *does not* map to the LLVM `va_end` intrinsic. +/// +/// This function is a no-op on all current targets, but used as a hook for const evaluation to +/// detect UB when a variable argument list is used incorrectly. /// /// # Safety /// @@ -3490,4 +3498,6 @@ pub unsafe fn va_arg(ap: &mut VaList<'_>) -> T; /// #[rustc_intrinsic] #[rustc_nounwind] -pub unsafe fn va_end(ap: &mut VaList<'_>); +pub unsafe fn va_end(ap: &mut VaList<'_>) { + /* deliberately does nothing */ +} diff --git a/tests/codegen-llvm/cffi/c-variadic-copy.rs b/tests/codegen-llvm/cffi/c-variadic-copy.rs deleted file mode 100644 index 0cbdcb4bbb85c..0000000000000 --- a/tests/codegen-llvm/cffi/c-variadic-copy.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Tests that `VaList::clone` gets inlined into a call to `llvm.va_copy` - -#![crate_type = "lib"] -#![feature(c_variadic)] -#![no_std] -use core::ffi::VaList; - -extern "C" { - fn foreign_c_variadic_1(_: VaList, ...); -} - -pub unsafe extern "C" fn clone_variadic(ap: VaList) { - let mut ap2 = ap.clone(); - // CHECK: call void @llvm.va_copy - foreign_c_variadic_1(ap2, 42i32); -} diff --git a/tests/codegen-llvm/cffi/c-variadic-opt.rs b/tests/codegen-llvm/cffi/c-variadic-opt.rs index 3cc0c3e9f9bdd..c779b25450fd1 100644 --- a/tests/codegen-llvm/cffi/c-variadic-opt.rs +++ b/tests/codegen-llvm/cffi/c-variadic-opt.rs @@ -17,14 +17,3 @@ pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 { vprintf(fmt, ap) // CHECK: call void @llvm.va_end } - -// Check that `VaList::clone` gets inlined into a direct call to `llvm.va_copy` -#[no_mangle] -pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 { - // CHECK: call void @llvm.va_start - let mut ap2 = ap.clone(); - // CHECK: call void @llvm.va_copy - let res = vprintf(fmt, ap2); - res - // CHECK: call void @llvm.va_end -} diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 3d51731df792d..f817a0b0d91b1 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -26,12 +26,6 @@ error[E0463]: can't find crate for `wloop` LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate -error: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:114:1 - | -LL | #[patchable_function_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` - error: malformed `allow` attribute input --> $DIR/malformed-attrs.rs:184:1 | @@ -444,6 +438,15 @@ LL | #[instruction_set] | = note: for more information, visit +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/malformed-attrs.rs:114:1 + | +LL | #[patchable_function_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + error[E0565]: malformed `coroutine` attribute input --> $DIR/malformed-attrs.rs:117:5 | diff --git a/tests/ui/c-variadic/copy.rs b/tests/ui/c-variadic/copy.rs new file mode 100644 index 0000000000000..e9171738aa157 --- /dev/null +++ b/tests/ui/c-variadic/copy.rs @@ -0,0 +1,24 @@ +//@ run-pass +//@ ignore-backends: gcc +#![feature(c_variadic)] + +// Test the behavior of `VaList::clone`. In C a `va_list` is duplicated using `va_copy`, but the +// rust api just uses `Clone`. This should create a completely independent cursor into the +// variable argument list: advancing the original has no effect on the copy and vice versa. + +fn main() { + unsafe { variadic(1, 2, 3) } +} + +unsafe extern "C" fn variadic(mut ap1: ...) { + let mut ap2 = ap1.clone(); + + assert_eq!(ap1.arg::(), 1); + assert_eq!(ap2.arg::(), 1); + + assert_eq!(ap2.arg::(), 2); + assert_eq!(ap1.arg::(), 2); + + drop(ap1); + assert_eq!(ap2.arg::(), 3); +} diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index f2ddc928d122e..0553b676bc3e9 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -10,7 +10,6 @@ impl<'a> Foo<'a> { const fn spam(&mut self, baz: &mut Vec) { self.bar[0] = baz.len(); //~^ ERROR: `Vec: [const] Index<_>` is not satisfied - //~| ERROR: `Vec: [const] Index` is not satisfied //~| ERROR: `Vec: [const] IndexMut` is not satisfied } } diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index 771f2a14c3053..ab7a76a90e02c 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -16,17 +16,6 @@ LL | self.bar[0] = baz.len(); note: trait `IndexMut` is implemented but not `const` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the trait bound `Vec: [const] Index` is not satisfied - --> $DIR/issue-94675.rs:11:9 - | -LL | self.bar[0] = baz.len(); - | ^^^^^^^^^^^ - | -note: trait `Index` is implemented but not `const` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -note: required by a bound in `std::ops::IndexMut::index_mut` - --> $SRC_DIR/core/src/ops/index.rs:LL:COL - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs index 17556723622ed..f3d5bcbd8d781 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs @@ -1,12 +1,14 @@ // Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate. -#[rustc_variance] -//~^ ERROR use of an internal attribute [E0658] -//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable -//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests #[rustc_nonnull_optimization_guaranteed] //~^ ERROR use of an internal attribute [E0658] //~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable //~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library //~| NOTE the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized fn main() {} + +#[rustc_variance] +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests +enum E {} diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 159d383e40891..6588229b7d56e 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -1,16 +1,6 @@ error[E0658]: use of an internal attribute --> $DIR/feature-gate-rustc-attrs-1.rs:3:1 | -LL | #[rustc_variance] - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable - = note: the `#[rustc_variance]` attribute is used for rustc unit tests - -error[E0658]: use of an internal attribute - --> $DIR/feature-gate-rustc-attrs-1.rs:7:1 - | LL | #[rustc_nonnull_optimization_guaranteed] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -19,6 +9,16 @@ LL | #[rustc_nonnull_optimization_guaranteed] = note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library = note: the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized +error[E0658]: use of an internal attribute + --> $DIR/feature-gate-rustc-attrs-1.rs:10:1 + | +LL | #[rustc_variance] + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_variance]` attribute is used for rustc unit tests + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs index ead2e3221d8cb..091ccdf38a081 100644 --- a/tests/ui/instrument-coverage/coverage-options.rs +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -1,5 +1,5 @@ //@ revisions: block branch condition bad -//@ compile-flags -Cinstrument-coverage -Zno-profiler-runtime +//@ compile-flags: -Cinstrument-coverage -Zno-profiler-runtime //@ [block] check-pass //@ [block] compile-flags: -Zcoverage-options=block diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs index 1e376c9ff3c1a..5cbeccf1b0e4f 100644 --- a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs +++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.rs @@ -1,17 +1,26 @@ #![feature(patchable_function_entry)] fn main() {} -#[patchable_function_entry(prefix_nops = 256, entry_nops = 0)]//~error: integer value out of range +#[patchable_function_entry(prefix_nops = 256, entry_nops = 0)] +//~^ ERROR malformed pub fn too_high_pnops() {} -#[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)]//~error: invalid literal value +#[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)] +//~^ ERROR malformed pub fn non_int_nop() {} -#[patchable_function_entry]//~error: malformed `patchable_function_entry` attribute input +#[patchable_function_entry] +//~^ ERROR malformed `patchable_function_entry` attribute input pub fn malformed_attribute() {} -#[patchable_function_entry(prefix_nops = 10, something = 0)]//~error: unexpected parameter name +#[patchable_function_entry(prefix_nops = 10, something = 0)] +//~^ ERROR malformed pub fn unexpected_parameter_name() {} -#[patchable_function_entry()]//~error: must specify at least one parameter +#[patchable_function_entry()] +//~^ ERROR malformed pub fn no_parameters_given() {} + +#[patchable_function_entry(prefix_nops = 255, prefix_nops = 255)] +//~^ ERROR malformed +pub fn duplicate_parameter() {} diff --git a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr index 9357a86c4153f..43fc0c0518af1 100644 --- a/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr +++ b/tests/ui/patchable-function-entry/patchable-function-entry-attribute.stderr @@ -1,32 +1,58 @@ -error: malformed `patchable_function_entry` attribute input - --> $DIR/patchable-function-entry-attribute.rs:10:1 - | -LL | #[patchable_function_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` - -error: integer value out of range - --> $DIR/patchable-function-entry-attribute.rs:4:42 +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:4:1 | LL | #[patchable_function_entry(prefix_nops = 256, entry_nops = 0)] - | ^^^ value must be between `0` and `255` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^^^^^^^^^^^^^^^^ + | | | + | | expected an integer literal in the range of 0..=255 + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: invalid literal value - --> $DIR/patchable-function-entry-attribute.rs:7:42 +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:8:1 | LL | #[patchable_function_entry(prefix_nops = "stringvalue", entry_nops = 0)] - | ^^^^^^^^^^^^^ value must be an integer between `0` and `255` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^^^^^^^^^^^^^^^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: unexpected parameter name - --> $DIR/patchable-function-entry-attribute.rs:13:46 +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:12:1 | -LL | #[patchable_function_entry(prefix_nops = 10, something = 0)] - | ^^^^^^^^^^^^^ expected `prefix_nops` or `entry_nops` +LL | #[patchable_function_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: must specify at least one parameter +error[E0539]: malformed `patchable_function_entry` attribute input --> $DIR/patchable-function-entry-attribute.rs:16:1 | +LL | #[patchable_function_entry(prefix_nops = 10, something = 0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^^^^ + | | | + | | valid arguments are `prefix_nops` or `entry_nops` + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + +error[E0539]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:20:1 + | LL | #[patchable_function_entry()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^--^ + | | | + | | expected this to be a list + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + +error[E0538]: malformed `patchable_function_entry` attribute input + --> $DIR/patchable-function-entry-attribute.rs:24:1 + | +LL | #[patchable_function_entry(prefix_nops = 255, prefix_nops = 255)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^ + | | | + | | found `prefix_nops` used as a key more than once + | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors +Some errors have detailed explanations: E0538, E0539. +For more information about an error, try `rustc --explain E0538`. diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index c36adc4248f03..360c08e1b7fe9 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -6,7 +6,6 @@ const _: () = { assert!((const || true)()); //~^ ERROR }: [const] Fn()` is not satisfied - //~| ERROR }: [const] FnMut()` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr index b688746e25068..8e32cab6dfcfb 100644 --- a/tests/ui/traits/const-traits/call.stderr +++ b/tests/ui/traits/const-traits/call.stderr @@ -4,15 +4,6 @@ error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] Fn()` LL | assert!((const || true)()); | ^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] FnMut()` is not satisfied - --> $DIR/call.rs:7:13 - | -LL | assert!((const || true)()); - | ^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `call` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr index 90e87c724f54d..dab3f14161fac 100644 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr +++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr @@ -4,15 +4,6 @@ error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice- LL | (const || (()).foo())(); | ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] FnMut()` is not satisfied - --> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5 - | -LL | (const || (()).foo())(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `call` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs index ee4ff02f4c7c2..de5bedf0ace76 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs @@ -10,7 +10,8 @@ impl Foo for () { } fn main() { + // #150052 deduplicate diagnostics for const trait supertraits + // so we only get one error here (const || { (()).foo() })(); //~^ ERROR: }: [const] Fn()` is not satisfied - //~| ERROR: }: [const] FnMut()` is not satisfied } diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index 69d289537da1d..efbedca1c7e7f 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -1,18 +1,9 @@ -error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:13:6: 13:14}: [const] Fn()` is not satisfied - --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:5 +error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:15:6: 15:14}: [const] Fn()` is not satisfied + --> $DIR/non-const-op-const-closure-non-const-outer.rs:15:5 | LL | (const || { (()).foo() })(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:13:6: 13:14}: [const] FnMut()` is not satisfied - --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:5 - | -LL | (const || { (()).foo() })(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `call` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`.