diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 3dedeb1b3726f..24f52d6f5002f 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -110,6 +110,22 @@ pub enum DeprecatedSince { Err, } +#[derive( + Copy, + Debug, + Eq, + PartialEq, + Encodable, + Decodable, + Clone, + HashStable_Generic, + PrintAttribute +)] +pub enum CoverageStatus { + On, + Off, +} + impl Deprecation { /// Whether an item marked with #[deprecated(since = "X")] is currently /// deprecated (i.e., whether X is not greater than the current rustc @@ -274,6 +290,9 @@ pub enum AttributeKind { /// Represents `#[const_trait]`. ConstTrait(Span), + /// Represents `#[coverage]`. + Coverage(Span, CoverageStatus), + ///Represents `#[rustc_deny_explicit_impl]`. DenyExplicitImpl(Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 3e2dc0a15b2f3..8105e4fb1255e 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -28,6 +28,7 @@ impl AttributeKind { ConstStability { .. } => Yes, ConstStabilityIndirect => No, ConstTrait(..) => No, + Coverage(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 34d9b04834825..3e542771d58c9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,4 +1,4 @@ -use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy}; +use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy}; use rustc_feature::{AttributeTemplate, template}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -52,6 +52,45 @@ impl NoArgsAttributeParser for ColdParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold; } +pub(crate) struct CoverageParser; + +impl SingleAttributeParser for CoverageParser { + const PATH: &[Symbol] = &[sym::coverage]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(args) = args.list() else { + cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]); + return None; + }; + + let Some(arg) = args.single() else { + cx.expected_single_argument(args.span); + return None; + }; + + let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]); + + let Some(arg) = arg.meta_item() else { + fail_incorrect_argument(args.span); + return None; + }; + + let status = match arg.path().word_sym() { + Some(sym::off) => CoverageStatus::Off, + Some(sym::on) => CoverageStatus::On, + None | Some(_) => { + fail_incorrect_argument(arg.span()); + return None; + } + }; + + Some(AttributeKind::Coverage(cx.attr_span, status)) + } +} + pub(crate) struct ExportNameParser; impl SingleAttributeParser for ExportNameParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 567341d1517dd..043a0524269ad 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,8 +15,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::codegen_attrs::{ - ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, - OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, + ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, + OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, + UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; @@ -136,6 +137,7 @@ attribute_parsers!( // tidy-alphabetical-end // tidy-alphabetical-start + Single, Single, Single, Single, @@ -449,6 +451,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { reason: AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: false, + list: false, + }, + }) + } + + pub(crate) fn expected_specific_argument_and_list( + &self, + span: Span, + possibilities: Vec<&'static str>, + ) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings: false, + list: true, }, }) } @@ -466,6 +487,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { reason: AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: true, + list: false, }, }) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 97bf3d1c54955..67dac8da3842f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -525,7 +525,9 @@ pub(crate) struct LinkOrdinalOutOfRange { pub(crate) enum AttributeParseErrorReason { ExpectedNoArgs, - ExpectedStringLiteral { byte_string: Option }, + ExpectedStringLiteral { + byte_string: Option, + }, ExpectedIntegerLiteral, ExpectedAtLeastOneArgument, ExpectedSingleArgument, @@ -533,7 +535,12 @@ pub(crate) enum AttributeParseErrorReason { UnexpectedLiteral, ExpectedNameValue(Option), DuplicateKey(Symbol), - ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool }, + ExpectedSpecificArgument { + possibilities: Vec<&'static str>, + strings: bool, + /// Should we tell the user to write a list when they didn't? + list: bool, + }, } pub(crate) struct AttributeParseError { @@ -607,7 +614,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { format!("expected this to be of the form `{name} = \"...\"`"), ); } - AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => { + AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings, + list: false, + } => { let quote = if strings { '"' } else { '`' }; match possibilities.as_slice() { &[] => {} @@ -633,6 +644,38 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { } } } + AttributeParseErrorReason::ExpectedSpecificArgument { + possibilities, + strings, + list: true, + } => { + let quote = if strings { '"' } else { '`' }; + match possibilities.as_slice() { + &[] => {} + &[x] => { + diag.span_label( + self.span, + format!( + "this attribute is only valid with {quote}{x}{quote} as an argument" + ), + ); + } + [first, second] => { + diag.span_label(self.span, format!("this attribute is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument")); + } + [first @ .., second_to_last, last] => { + let mut res = String::new(); + for i in first { + res.push_str(&format!("{quote}{i}{quote}, ")); + } + res.push_str(&format!( + "{quote}{second_to_last}{quote} or {quote}{last}{quote}" + )); + + diag.span_label(self.span, format!("this attribute is only valid with one of the following arguments: {res}")); + } + } + } } let suggestions = self.template.suggestions(false, &name); diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index a98e9c6d1c7fc..dd8f0e46a0e03 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -23,6 +23,7 @@ pub(crate) fn expand_deriving_copy( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); @@ -46,6 +47,7 @@ pub(crate) fn expand_deriving_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); @@ -60,6 +62,7 @@ pub(crate) fn expand_deriving_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); @@ -83,6 +86,7 @@ pub(crate) fn expand_deriving_unsized_const_param_ty( methods: Vec::new(), associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 69f8c273797e4..3c78f53c5cb0a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -87,6 +87,7 @@ pub(crate) fn expand_deriving_clone( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand_ext(cx, mitem, item, push, is_simple) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index eca79e4dc4897..29d531219a69c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -43,6 +43,7 @@ pub(crate) fn expand_deriving_eq( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand_ext(cx, mitem, item, push, true) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 1ed44c20bc61e..0e1ecf3118ac3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -34,6 +34,7 @@ pub(crate) fn expand_deriving_ord( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index b1d950b8d89de..990835fa27739 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -30,6 +30,7 @@ pub(crate) fn expand_deriving_partial_eq( methods: Vec::new(), associated_types: Vec::new(), is_const: false, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; structural_trait_def.expand(cx, mitem, item, push); @@ -58,6 +59,7 @@ pub(crate) fn expand_deriving_partial_eq( methods, associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 0a076dd670b34..f5d262ece36e3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -64,6 +64,7 @@ pub(crate) fn expand_deriving_partial_ord( methods: vec![partial_cmp_def], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 8ab21986e68a0..1d63ce7d5fd27 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_debug( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 1fe567e23f455..b4e2d27fed333 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -51,6 +51,7 @@ pub(crate) fn expand_deriving_default( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; trait_def.expand(cx, mitem, item, push) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index c55a9e73e3822..b24e55637613a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -181,9 +181,11 @@ use std::{iter, vec}; pub(crate) use StaticFields::*; pub(crate) use SubstructureFields::*; use rustc_ast::ptr::P; +use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind}; +use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ - self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, - Generics, Mutability, PatKind, VariantData, + self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, + GenericParamKind, Generics, Mutability, PatKind, Safety, VariantData, }; use rustc_attr_data_structures::{AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; @@ -222,6 +224,8 @@ pub(crate) struct TraitDef<'a> { pub associated_types: Vec<(Ident, Ty)>, pub is_const: bool, + + pub is_staged_api_crate: bool, } pub(crate) struct MethodDef<'a> { @@ -784,8 +788,45 @@ impl<'a> TraitDef<'a> { // Create the type of `self`. let path = cx.path_all(self.span, false, vec![type_ident], self_params); let self_type = cx.ty_path(path); + let rustc_const_unstable = + cx.path_ident(self.span, Ident::new(sym::rustc_const_unstable, self.span)); + + let mut attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; + + // Only add `rustc_const_unstable` attributes if `derive_const` is used within libcore/libstd, + // Other crates don't need stability attributes, so adding them is not useful, but libcore needs them + // on all const trait impls. + if self.is_const && self.is_staged_api_crate { + attrs.push( + cx.attr_nested( + rustc_ast::AttrItem { + unsafety: Safety::Default, + path: rustc_const_unstable, + args: AttrArgs::Delimited(DelimArgs { + dspan: DelimSpan::from_single(self.span), + delim: rustc_ast::token::Delimiter::Parenthesis, + tokens: [ + TokenKind::Ident(sym::feature, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const, None), + TokenKind::Comma, + TokenKind::Ident(sym::issue, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const_issue, None), + ] + .into_iter() + .map(|kind| { + TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone) + }) + .collect(), + }), + tokens: None, + }, + self.span, + ), + ) + } - let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; let opt_trait_ref = Some(trait_ref); cx.item( diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6e6dbe19e4d1a..78534449895c2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -41,6 +41,7 @@ pub(crate) fn expand_deriving_hash( }], associated_types: Vec::new(), is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), }; hash_trait_def.expand(cx, mitem, item, push); diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 203b443269fa7..ec9d00f92e5d5 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -8,10 +8,10 @@ use std::sync::Arc; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef}; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, }; +use rustc_middle::ty::{Instance, TyCtxt}; use rustc_session::config::{OutputFilenames, OutputType}; use rustc_target::asm::InlineAsmArch; @@ -29,6 +29,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span], + _instance: Instance<'_>, ) { codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options); } @@ -104,7 +105,7 @@ fn codegen_global_asm_inner<'tcx>( InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s), InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => { match operands[operand_idx] { - GlobalAsmOperandRef::Const { ref string } => { + GlobalAsmOperandRef::Interpolate { ref string } => { global_asm.push_str(string); } GlobalAsmOperandRef::SymFn { instance } => { @@ -132,6 +133,12 @@ fn codegen_global_asm_inner<'tcx>( let symbol = tcx.symbol_name(instance); global_asm.push_str(symbol.name); } + GlobalAsmOperandRef::ConstPointer { value: _ } => { + tcx.dcx().span_err( + span, + "asm! and global_asm! const pointer operands are not yet supported", + ); + } } } } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 17e2e028b16fa..8be7298125cb1 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; -use gccjit::{LValue, RValue, ToRValue, Type}; +use gccjit::{GlobalKind, LValue, RValue, ToRValue, Type}; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -10,8 +10,8 @@ use rustc_codegen_ssa::traits::{ AsmBuilderMethods, AsmCodegenMethods, BaseTypeCodegenMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef, }; -use rustc_middle::bug; use rustc_middle::ty::Instance; +use rustc_middle::{bug, mir}; use rustc_span::Span; use rustc_target::asm::*; @@ -296,10 +296,18 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } } - InlineAsmOperandRef::Const { ref string } => { + InlineAsmOperandRef::Interpolate { ref string } => { constants_len += string.len() + att_dialect as usize; } + InlineAsmOperandRef::Const { value } => { + inputs.push(AsmInOperand { + constraint: Cow::Borrowed("i"), + rust_idx, + val: value.immediate(), + }); + } + InlineAsmOperandRef::SymFn { instance } => { // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) @@ -411,6 +419,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }); } + InlineAsmOperandRef::Interpolate { .. } => { + // processed in the previous pass + } + InlineAsmOperandRef::Const { .. } => { // processed in the previous pass } @@ -488,6 +500,15 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { push_to_template(modifier, gcc_index); } + InlineAsmOperandRef::Const { .. } => { + let in_gcc_index = inputs + .iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + let gcc_index = in_gcc_index + outputs.len(); + push_to_template(None, gcc_index); + } + InlineAsmOperandRef::SymFn { instance } => { // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) @@ -504,7 +525,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { template_str.push_str(name); } - InlineAsmOperandRef::Const { ref string } => { + InlineAsmOperandRef::Interpolate { ref string } => { template_str.push_str(string); } @@ -837,6 +858,7 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span], + instance: Instance<'tcx>, ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); @@ -844,6 +866,102 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let att_dialect = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) && options.contains(InlineAsmOptions::ATT_SYNTAX); + // Convert all operands to string interpolations + let converted_operands = operands + .iter() + .enumerate() + .map(|(operand_idx, operand)| { + match *operand { + GlobalAsmOperandRef::Interpolate { ref string } => { + // Const operands get injected directly into the + // template. Note that we don't need to escape $ + // here unlike normal inline assembly. + string.to_owned() + } + GlobalAsmOperandRef::ConstPointer { value } => { + let (prov, offset) = value.prov_and_relative_offset(); + let global_alloc = self.tcx.global_alloc(prov.alloc_id()); + let symbol = 'sym: { + let alloc = match global_alloc { + mir::interpret::GlobalAlloc::Function { instance } => { + let function = get_fn(self, instance); + self.add_used_function(function); + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). + break 'sym self.tcx.symbol_name(instance).name.to_owned(); + } + mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self + .tcx + .global_alloc(self.tcx.vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx + .instantiate_bound_regions_with_erased(principal) + }), + ))) + .unwrap_memory(), + mir::interpret::GlobalAlloc::Static(def_id) => { + // TODO(antoyo): set the global variable as used. + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O). + let instance = Instance::mono(self.tcx, def_id); + break 'sym self.tcx.symbol_name(instance).name.to_owned(); + } + mir::interpret::GlobalAlloc::Memory(alloc) => alloc, + mir::interpret::GlobalAlloc::TypeId { .. } => { + // This is not an actual allocation, just return the offset. + return format!("{}", offset.bytes()); + } + }; + + // For ZSTs directly codegen an aligned pointer. + if alloc.inner().len() == 0 { + assert_eq!(offset.bytes(), 0); + return format!("{}", alloc.inner().align.bytes()); + } + + let asm_name = self.tcx.symbol_name(instance); + let sym_name = format!("{asm_name}.{operand_idx}"); + + let init = crate::consts::const_alloc_to_gcc_uncached(self, alloc); + let alloc = alloc.inner(); + let typ = self.val_ty(init).get_aligned(alloc.align.bytes()); + + let global = self.declare_global_with_linkage( + &sym_name, + typ, + GlobalKind::Exported, + ); + global.global_set_initializer_rvalue(init); + // TODO(nbdd0121): set unnamed address. + // TODO(nbdd0121): set the global variable as used. + + sym_name + }; + + let offset = offset.bytes(); + if offset != 0 { format!("{symbol}+{offset}") } else { symbol } + } + GlobalAsmOperandRef::SymFn { instance } => { + let function = get_fn(self, instance); + self.add_used_function(function); + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). + self.tcx.symbol_name(instance).name.to_owned() + } + GlobalAsmOperandRef::SymStatic { def_id } => { + // TODO(antoyo): set the global variable as used. + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O). + let instance = Instance::mono(self.tcx, def_id); + self.tcx.symbol_name(instance).name.to_owned() + } + } + }) + .collect::>(); + // Build the template string let mut template_str = ".pushsection .text\n".to_owned(); if att_dialect { @@ -867,33 +985,7 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { - match operands[operand_idx] { - GlobalAsmOperandRef::Const { ref string } => { - // Const operands get injected directly into the - // template. Note that we don't need to escape % - // here unlike normal inline assembly. - template_str.push_str(string); - } - - GlobalAsmOperandRef::SymFn { instance } => { - let function = get_fn(self, instance); - self.add_used_function(function); - // TODO(@Amanieu): Additional mangling is needed on - // some targets to add a leading underscore (Mach-O) - // or byte count suffixes (x86 Windows). - let name = self.tcx.symbol_name(instance).name; - template_str.push_str(name); - } - - GlobalAsmOperandRef::SymStatic { def_id } => { - // TODO(antoyo): set the global variable as used. - // TODO(@Amanieu): Additional mangling is needed on - // some targets to add a leading underscore (Mach-O). - let instance = Instance::mono(self.tcx, def_id); - let name = self.tcx.symbol_name(instance).name; - template_str.push_str(name); - } - } + template_str.push_str(&converted_operands[operand_idx]); } } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a643a91141e19..20bb037d4b7be 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::{bug, span_bug}; +use rustc_middle::{bug, mir, span_bug}; use rustc_span::{Pos, Span, Symbol, sym}; use rustc_target::asm::*; use smallvec::SmallVec; @@ -158,6 +158,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { constraints.push(format!("{}", op_idx[&idx])); } } + InlineAsmOperandRef::Const { value } => { + inputs.push(value.immediate()); + op_idx.insert(idx, constraints.len()); + constraints.push("i".to_string()); + } InlineAsmOperandRef::SymFn { instance } => { inputs.push(self.cx.get_fn(instance)); op_idx.insert(idx, constraints.len()); @@ -205,7 +210,10 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { template_str.push_str(&format!("${{{}}}", op_idx[&operand_idx])); } } - InlineAsmOperandRef::Const { ref string } => { + InlineAsmOperandRef::Const { .. } => { + template_str.push_str(&format!("${{{}:c}}", op_idx[&operand_idx])); + } + InlineAsmOperandRef::Interpolate { ref string } => { // Const operands get injected directly into the template template_str.push_str(string); } @@ -381,9 +389,119 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span], + instance: Instance<'tcx>, ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); + // Convert all operands to string interpolations + let converted_operands = operands + .iter() + .enumerate() + .map(|(operand_idx, operand)| { + match *operand { + GlobalAsmOperandRef::Interpolate { ref string } => { + // Const operands get injected directly into the + // template. Note that we don't need to escape $ + // here unlike normal inline assembly. + string.to_owned() + } + GlobalAsmOperandRef::ConstPointer { value } => { + let (prov, offset) = value.prov_and_relative_offset(); + let global_alloc = self.tcx.global_alloc(prov.alloc_id()); + let llval = 'llval: { + let alloc = match global_alloc { + mir::interpret::GlobalAlloc::Function { instance } => { + break 'llval self.get_fn(instance); + } + mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self + .tcx + .global_alloc(self.tcx.vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx + .instantiate_bound_regions_with_erased(principal) + }), + ))) + .unwrap_memory(), + mir::interpret::GlobalAlloc::Static(def_id) => { + break 'llval self + .renamed_statics + .borrow() + .get(&def_id) + .copied() + .unwrap_or_else(|| self.get_static(def_id)); + } + mir::interpret::GlobalAlloc::Memory(alloc) => alloc, + mir::interpret::GlobalAlloc::TypeId { .. } => { + // This is not an actual allocation, just return the offset. + return format!("{}", offset.bytes()); + } + }; + let alloc = alloc.inner(); + + // For ZSTs directly codegen an aligned pointer. + if alloc.len() == 0 { + assert_eq!(offset.bytes(), 0); + return format!("{}", alloc.align.bytes()); + } + + let asm_name = self.tcx.symbol_name(instance); + let sym_name = format!("{asm_name}.{operand_idx}"); + + let init = crate::consts::const_alloc_to_llvm( + self, alloc, /*static*/ false, + ); + let g = self.static_addr_of_mut(init, alloc.align, None); + if alloc.mutability.is_not() { + // NB: we can't use `static_addr_of_impl` here to avoid sharing + // the global, as we need to set name and linkage. + unsafe { llvm::LLVMSetGlobalConstant(g, llvm::True) }; + } + + llvm::set_value_name(g, sym_name.as_bytes()); + + // `static_addr_of_mut` gives us a private global which can't be + // used by global asm. Update it to a hidden internal global instead. + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + llvm::set_visibility(g, llvm::Visibility::Hidden); + g + }; + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + + let offset = offset.bytes(); + if offset != 0 { format!("{symbol}+{offset}") } else { symbol } + } + GlobalAsmOperandRef::SymFn { instance } => { + let llval = self.get_fn(instance); + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + symbol + } + GlobalAsmOperandRef::SymStatic { def_id } => { + let llval = self + .renamed_statics + .borrow() + .get(&def_id) + .copied() + .unwrap_or_else(|| self.get_static(def_id)); + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + symbol + } + } + }) + .collect::>(); + // Build the template string let mut template_str = String::new(); @@ -401,37 +519,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { match *piece { InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s), InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { - match operands[operand_idx] { - GlobalAsmOperandRef::Const { ref string } => { - // Const operands get injected directly into the - // template. Note that we don't need to escape $ - // here unlike normal inline assembly. - template_str.push_str(string); - } - GlobalAsmOperandRef::SymFn { instance } => { - let llval = self.get_fn(instance); - self.add_compiler_used_global(llval); - let symbol = llvm::build_string(|s| unsafe { - llvm::LLVMRustGetMangledName(llval, s); - }) - .expect("symbol is not valid UTF-8"); - template_str.push_str(&symbol); - } - GlobalAsmOperandRef::SymStatic { def_id } => { - let llval = self - .renamed_statics - .borrow() - .get(&def_id) - .copied() - .unwrap_or_else(|| self.get_static(def_id)); - self.add_compiler_used_global(llval); - let symbol = llvm::build_string(|s| unsafe { - llvm::LLVMRustGetMangledName(llval, s); - }) - .expect("symbol is not valid UTF-8"); - template_str.push_str(&symbol); - } - } + template_str.push_str(&converted_operands[operand_idx]) } } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 506286fc2559b..313bf6d20a662 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -879,9 +879,7 @@ pub(crate) fn codegen( .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); let thin_bc = module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); - unsafe { - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); - } + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); } } @@ -945,7 +943,7 @@ pub(crate) fn codegen( // binaries. So we must clone the module to produce the asm output // if we are also producing object code. let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { - unsafe { llvm::LLVMCloneModule(llmod) } + llvm::LLVMCloneModule(llmod) } else { llmod }; @@ -1073,7 +1071,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> } /// Embed the bitcode of an LLVM module for LTO in the LLVM module itself. -unsafe fn embed_bitcode( +fn embed_bitcode( cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module, @@ -1115,43 +1113,40 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - unsafe { - if cgcx.target_is_like_darwin - || cgcx.target_is_like_aix - || cgcx.target_arch == "wasm32" - || cgcx.target_arch == "wasm64" - { - // We don't need custom section flags, create LLVM globals. - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); - llvm::set_initializer(llglobal, llconst); - - llvm::set_section(llglobal, bitcode_section_name(cgcx)); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); - llvm::set_initializer(llglobal, llconst); - let section = if cgcx.target_is_like_darwin { - c"__LLVM,__cmdline" - } else if cgcx.target_is_like_aix { - c".info" - } else { - c".llvmcmd" - }; - llvm::set_section(llglobal, section); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + + if cgcx.target_is_like_darwin + || cgcx.target_is_like_aix + || cgcx.target_arch == "wasm32" + || cgcx.target_arch == "wasm64" + { + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); + llvm::set_initializer(llglobal, llconst); + + llvm::set_section(llglobal, bitcode_section_name(cgcx)); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); + llvm::set_initializer(llglobal, llconst); + let section = if cgcx.target_is_like_darwin { + c"__LLVM,__cmdline" + } else if cgcx.target_is_like_aix { + c".info" } else { - // We need custom section flags, so emit module-level inline assembly. - let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; - let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::append_module_inline_asm(llmod, &asm); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::append_module_inline_asm(llmod, &asm); - } + c".llvmcmd" + }; + llvm::set_section(llglobal, section); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + } else { + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::append_module_inline_asm(llmod, &asm); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + llvm::append_module_inline_asm(llmod, &asm); } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9c3b866aa3c6f..514923ad6f37f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -302,10 +302,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - let id_str = "branch_weights"; - let id = unsafe { - llvm::LLVMMDStringInContext2(self.cx.llcx, id_str.as_ptr().cast(), id_str.len()) - }; + let id = self.cx.create_metadata(b"branch_weights"); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to @@ -637,17 +634,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } else if place.layout.is_llvm_immediate() { let mut const_llval = None; let llty = place.layout.llvm_type(self); - unsafe { - if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { - if llvm::LLVMIsGlobalConstant(global) == llvm::True { - if let Some(init) = llvm::LLVMGetInitializer(global) { - if self.val_ty(init) == llty { - const_llval = Some(init); - } + if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { + if llvm::LLVMIsGlobalConstant(global) == llvm::True { + if let Some(init) = llvm::LLVMGetInitializer(global) { + if self.val_ty(init) == llty { + const_llval = Some(init); } } } } + let llval = const_llval.unwrap_or_else(|| { let load = self.load(llty, place.val.llval, place.val.align); if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { @@ -1721,7 +1717,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.cx.create_metadata(typeid.as_bytes()); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 5afb9a60d4241..dff6847284736 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); + let enzyme_const = cx.create_metadata(b"enzyme_const"); + let enzyme_out = cx.create_metadata(b"enzyme_out"); + let enzyme_dup = cx.create_metadata(b"enzyme_dup"); + let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); + let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); + let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); + let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); + let enzyme_width = cx.create_metadata(b"enzyme_width"); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b9b5c776d86aa..f9ab96b578951 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -215,10 +215,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { bug!("symbol `{}` is already defined", sym); }); llvm::set_initializer(g, sc); - unsafe { - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - } + + llvm::set_global_constant(g, true); + llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); // Cast to default address space if globals are in a different addrspace let g = self.const_pointercast(g, self.type_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5deddb3ed9819..0b96b63bc8573 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -17,13 +17,12 @@ use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; -use crate::common::{AsCCharPtr, CodegenCx}; +use crate::common::CodegenCx; use crate::errors::SymbolAlreadyDefined; -use crate::llvm::{self, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use crate::{base, debuginfo}; +use crate::{base, debuginfo, llvm}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, @@ -247,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> { }; llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); - llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global); gv } @@ -272,9 +271,8 @@ impl<'ll> CodegenCx<'ll, '_> { return gv; } let gv = self.static_addr_of_mut(cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } + llvm::set_global_constant(gv, true); + self.const_globals.borrow_mut().insert(cv, gv); gv } @@ -398,149 +396,140 @@ impl<'ll> CodegenCx<'ll, '_> { } fn codegen_static_item(&mut self, def_id: DefId) { - unsafe { - assert!( - llvm::LLVMGetInitializer( - self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() - ) - .is_none() - ); - let attrs = self.tcx.codegen_fn_attrs(def_id); + assert!( + llvm::LLVMGetInitializer( + self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() + ) + .is_none() + ); + let attrs = self.tcx.codegen_fn_attrs(def_id); - let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { - // Error has already been reported - return; - }; - let alloc = alloc.inner(); + let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { + // Error has already been reported + return; + }; + let alloc = alloc.inner(); - let val_llty = self.val_ty(v); + let val_llty = self.val_ty(v); - let g = self.get_static_inner(def_id, val_llty); - let llty = self.get_type_of_global(g); + let g = self.get_static_inner(def_id, val_llty); + let llty = self.get_type_of_global(g); - let g = if val_llty == llty { - g - } else { - // codegen_static_initializer creates the global value just from the - // `Allocation` data by generating one big struct value that is just - // all the bytes and pointers after each other. This will almost never - // match the type that the static was declared with. Unfortunately - // we can't just LLVMConstBitCast our way out of it because that has very - // specific rules on what can be cast. So instead of adding a new way to - // generate static initializers that match the static's type, we picked - // the easier option and retroactively change the type of the static item itself. - let name = llvm::get_value_name(g); - llvm::set_value_name(g, b""); - - let linkage = llvm::get_linkage(g); - let visibility = llvm::get_visibility(g); - - let new_g = llvm::LLVMRustGetOrInsertGlobal( - self.llmod, - name.as_c_char_ptr(), - name.len(), - val_llty, - ); - - llvm::set_linkage(new_g, linkage); - llvm::set_visibility(new_g, visibility); - - // The old global has had its name removed but is returned by - // get_static since it is in the instance cache. Provide an - // alternative lookup that points to the new global so that - // global_asm! can compute the correct mangled symbol name - // for the global. - self.renamed_statics.borrow_mut().insert(def_id, new_g); - - // To avoid breaking any invariants, we leave around the old - // global for the moment; we'll replace all references to it - // with the new global later. (See base::codegen_backend.) - self.statics_to_rauw.borrow_mut().push((g, new_g)); - new_g - }; - set_global_alignment(self, g, alloc.align); - llvm::set_initializer(g, v); - - self.assume_dso_local(g, true); - - // Forward the allocation's mutability (picked by the const interner) to LLVM. - if alloc.mutability.is_not() { - llvm::LLVMSetGlobalConstant(g, llvm::True); - } + let g = if val_llty == llty { + g + } else { + // codegen_static_initializer creates the global value just from the + // `Allocation` data by generating one big struct value that is just + // all the bytes and pointers after each other. This will almost never + // match the type that the static was declared with. Unfortunately + // we can't just LLVMConstBitCast our way out of it because that has very + // specific rules on what can be cast. So instead of adding a new way to + // generate static initializers that match the static's type, we picked + // the easier option and retroactively change the type of the static item itself. + let name = String::from_utf8(llvm::get_value_name(g)) + .expect("we declare our statics with a utf8-valid name"); + llvm::set_value_name(g, b""); + + let linkage = llvm::get_linkage(g); + let visibility = llvm::get_visibility(g); + + let new_g = self.declare_global(&name, val_llty); + + llvm::set_linkage(new_g, linkage); + llvm::set_visibility(new_g, visibility); + + // The old global has had its name removed but is returned by + // get_static since it is in the instance cache. Provide an + // alternative lookup that points to the new global so that + // global_asm! can compute the correct mangled symbol name + // for the global. + self.renamed_statics.borrow_mut().insert(def_id, new_g); + + // To avoid breaking any invariants, we leave around the old + // global for the moment; we'll replace all references to it + // with the new global later. (See base::codegen_backend.) + self.statics_to_rauw.borrow_mut().push((g, new_g)); + new_g + }; + set_global_alignment(self, g, alloc.align); + llvm::set_initializer(g, v); - debuginfo::build_global_var_di_node(self, def_id, g); + self.assume_dso_local(g, true); - if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { - llvm::set_thread_local_mode(g, self.tls_model); - } + // Forward the allocation's mutability (picked by the const interner) to LLVM. + if alloc.mutability.is_not() { + llvm::set_global_constant(g, true); + } - // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. The exception to this - // is the `.init_array` section which are treated specially by the wasm linker. - if self.tcx.sess.target.is_like_wasm - && attrs - .link_section - .map(|link_section| !link_section.as_str().starts_with(".init_array")) - .unwrap_or(true) - { - if let Some(section) = attrs.link_section { - let section = llvm::LLVMMDStringInContext2( - self.llcx, - section.as_str().as_c_char_ptr(), - section.as_str().len(), - ); - assert!(alloc.provenance().ptrs().is_empty()); - - // The `inspect` method is okay here because we checked for provenance, and - // because we are doing this access to inspect the final interpreter state (not - // as part of the interpreter execution). - let bytes = - alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); - let data = [section, alloc]; - let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = self.get_metadata_value(meta); + debuginfo::build_global_var_di_node(self, def_id, g); + + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + llvm::set_thread_local_mode(g, self.tls_model); + } + + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { + if let Some(section) = attrs.link_section { + let section = self.create_metadata(section.as_str().as_bytes()); + assert!(alloc.provenance().ptrs().is_empty()); + + // The `inspect` method is okay here because we checked for provenance, and + // because we are doing this access to inspect the final interpreter state (not + // as part of the interpreter execution). + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); + let alloc = self.create_metadata(bytes); + let data = [section, alloc]; + let meta = + unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; + let val = self.get_metadata_value(meta); + unsafe { llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), val, - ); - } - } else { - base::set_link_section(g, attrs); + ) + }; } + } else { + base::set_link_section(g, attrs); + } - base::set_variable_sanitizer_attrs(g, attrs); - - if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); - - // The semantics of #[used] in Rust only require the symbol to make it into the - // object file. It is explicitly allowed for the linker to strip the symbol if it - // is dead, which means we are allowed to use `llvm.compiler.used` instead of - // `llvm.used` here. - // - // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique - // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs - // in the handling of `.init_array` (the static constructor list) in versions of - // the gold linker (prior to the one released with binutils 2.36). - // - // That said, we only ever emit these when `#[used(compiler)]` is explicitly - // requested. This is to avoid similar breakage on other targets, in particular - // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` - // is emitted rather than `llvm.used`. However, that check happens when assigning - // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to - // take care of it here. - self.add_compiler_used_global(g); - } - if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); + base::set_variable_sanitizer_attrs(g, attrs); + + if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + + // The semantics of #[used] in Rust only require the symbol to make it into the + // object file. It is explicitly allowed for the linker to strip the symbol if it + // is dead, which means we are allowed to use `llvm.compiler.used` instead of + // `llvm.used` here. + // + // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique + // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs + // in the handling of `.init_array` (the static constructor list) in versions of + // the gold linker (prior to the one released with binutils 2.36). + // + // That said, we only ever emit these when `#[used(compiler)]` is explicitly + // requested. This is to avoid similar breakage on other targets, in particular + // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` + // is emitted rather than `llvm.used`. However, that check happens when assigning + // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to + // take care of it here. + self.add_compiler_used_global(g); + } + if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); - self.add_used_global(g); - } + self.add_used_global(g); } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 90582e23b04cf..6a23becaa96ff 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,6 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm::Metadata; use crate::type_::Type; @@ -169,6 +168,8 @@ pub(crate) unsafe fn create_module<'ll>( let mod_name = SmallCStr::new(mod_name); let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; + let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()); + let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); @@ -473,18 +474,14 @@ pub(crate) unsafe fn create_module<'ll>( #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = unsafe { - llvm::LLVMMDStringInContext2( - llcx, - rustc_producer.as_c_char_ptr(), - rustc_producer.as_bytes().len(), - ) - }; + + let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); + unsafe { llvm::LLVMAddNamedMetadataOperand( llmod, c"llvm.ident".as_ptr(), - &llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), + &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), ); } @@ -698,10 +695,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { - Some(unsafe { + pub(crate) fn create_metadata(&self, name: &[u8]) -> &'ll Metadata { + unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) - }) + } } pub(crate) fn get_functions(&self) -> Vec<&'ll Value> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 49ee96a41d696..61555ac2f6f6e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -74,7 +74,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::set_initializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); - llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9b4736e50e6c3..0e9dbfba658d2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{iter, ptr}; -use libc::{c_char, c_longlong, c_uint}; +use libc::{c_longlong, c_uint}; use rustc_abi::{Align, Size}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; @@ -1582,13 +1582,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); + let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); unsafe { - let typeid = llvm::LLVMMDStringInContext2( - cx.llcx, - trait_ref_typeid.as_ptr() as *const c_char, - trait_ref_typeid.as_bytes().len(), - ); let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; llvm::LLVMRustGlobalAddMetadata( vtable, @@ -1630,7 +1626,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( // When full debuginfo is enabled, we want to try and prevent vtables from being // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. - llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No); + llvm::set_unnamed_address(vtable, llvm::UnnamedAddr::No); let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 2419ec1f88854..eb75716d768bb 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -49,7 +49,7 @@ pub(crate) fn declare_simple_fn<'ll>( }; llvm::SetFunctionCallConv(llfn, callconv); - llvm::SetUnnamedAddress(llfn, unnamed); + llvm::set_unnamed_address(llfn, unnamed); llvm::set_visibility(llfn, visibility); llfn @@ -176,7 +176,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { { let typeid = cfi::typeid_for_instance(self.tcx, instance, options); if typeids.insert(typeid.clone()) { - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } else { @@ -189,7 +189,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { .map(cfi::TypeIdOptions::from_iter) { let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 5c34ab2e3040d..0b1e632cbc42c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1009,7 +1009,7 @@ unsafe extern "C" { ModuleID: *const c_char, C: &Context, ) -> &Module; - pub(crate) fn LLVMCloneModule(M: &Module) -> &Module; + pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; /// Data layout. See Module::getDataLayout. pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char; @@ -1168,18 +1168,18 @@ unsafe extern "C" { pub(crate) fn LLVMGlobalGetValueType(Global: &Value) -> &Type; // Operations on global variables - pub(crate) fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>; pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>; pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMDeleteGlobal(GlobalVar: &Value); - pub(crate) fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value); - pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); - pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; - pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); + pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes @@ -1718,7 +1718,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; - pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); + pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); pub(crate) fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 3fc83fca352a8..154ba4fd69018 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -217,10 +217,8 @@ pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) { set_comdat(llmod, val, &name); } -pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) { - unsafe { - LLVMSetUnnamedAddress(global, unnamed); - } +pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) { + LLVMSetUnnamedAddress(global, unnamed); } pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) { @@ -260,9 +258,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { } pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) { - unsafe { - LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); - } + LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); } pub(crate) fn get_linkage(llglobal: &Value) -> Linkage { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191bf2..8f70270f203e7 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -131,8 +131,8 @@ impl CodegenCx<'_, '_> { } // Thread-local variables generally don't support copy relocations. - let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) } - .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True); + let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) + .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); if is_thread_local_var { return false; } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ee472e75ed41e..893655031388c 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use std::hash::{Hash, Hasher}; use std::{fmt, ptr}; -use libc::{c_char, c_uint}; +use libc::c_uint; use rustc_abi::{AddressSpace, Align, Integer, Reg, Size}; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -298,8 +298,8 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn add_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMRustGlobalAddMetadata( @@ -310,8 +310,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn set_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMGlobalSetMetadata( @@ -322,10 +322,8 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { - Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len()) - }) + fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { + Some(self.create_metadata(typeid)) } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 18581f854b664..e3f4c1db91482 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -19,9 +19,9 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; use rustc_middle::middle::lang_items; -use rustc_middle::mir::BinOp; -use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::interpret::{ErrorHandled, Scalar}; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions}; +use rustc_middle::mir::{BinOp, ConstValue}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -409,20 +409,34 @@ where Ok(const_value) => { let ty = cx.tcx().typeck_body(anon_const.body).node_type(anon_const.hir_id); - let string = common::asm_const_to_str( - cx.tcx(), - *op_sp, - const_value, - cx.layout_of(ty), - ); - GlobalAsmOperandRef::Const { string } + let ConstValue::Scalar(scalar) = const_value else { + span_bug!( + *op_sp, + "expected Scalar for promoted asm const, but got {:#?}", + const_value + ) + }; + match scalar { + Scalar::Int(_) => { + let string = common::asm_const_to_str( + cx.tcx(), + *op_sp, + const_value, + cx.layout_of(ty), + ); + GlobalAsmOperandRef::Interpolate { string } + } + Scalar::Ptr(value, _) => { + GlobalAsmOperandRef::ConstPointer { value } + } + } } Err(ErrorHandled::Reported { .. }) => { // An error has already been reported and // compilation is guaranteed to fail if execution // hits this path. So an empty string instead of // a stringified constant value will suffice. - GlobalAsmOperandRef::Const { string: String::new() } + GlobalAsmOperandRef::Interpolate { string: String::new() } } Err(ErrorHandled::TooGeneric(_)) => { span_bug!(*op_sp, "asm const cannot be resolved; too generic") @@ -457,7 +471,13 @@ where }) .collect(); - cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans); + cx.codegen_global_asm( + asm.template, + &operands, + asm.options, + asm.line_spans, + Instance::mono(cx.tcx(), item_id.owner_id.to_def_id()), + ); } else { span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") } diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 48565e0b4de47..d9247fe2965c0 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -156,7 +156,7 @@ pub fn asm_const_to_str<'tcx>( }; let value = scalar.assert_scalar_int().to_bits(ty_and_layout.size); match ty_and_layout.ty.kind() { - ty::Uint(_) => value.to_string(), + ty::Uint(_) | ty::RawPtr(..) | ty::Ref(..) => value.to_string(), ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) { ty::IntTy::I8 => (value as i8).to_string(), ty::IntTy::I16 => (value as i16).to_string(), diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 2aa5c3c27ea52..34ad35a729b98 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -139,7 +139,8 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( && bx.cx().sess().lto() == Lto::Fat { if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { - let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); + let typeid = + bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap(); let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); return func; } else if nonnull { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bde63fd501aa2..752980358837d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1186,14 +1186,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { InlineAsmOperandRef::InOut { reg, late, in_value, out_place } } mir::InlineAsmOperand::Const { ref value } => { - let const_value = self.eval_mir_constant(value); - let string = common::asm_const_to_str( - bx.tcx(), - span, - const_value, - bx.layout_of(value.ty()), - ); - InlineAsmOperandRef::Const { string } + if value.ty().is_any_ptr() { + let value = self.eval_mir_constant_to_operand(bx, value); + InlineAsmOperandRef::Const { value } + } else { + let const_value = self.eval_mir_constant(value); + let string = common::asm_const_to_str( + bx.tcx(), + span, + const_value, + bx.layout_of(value.ty()), + ); + InlineAsmOperandRef::Interpolate { string } + } } mir::InlineAsmOperand::SymFn { ref value } => { let const_ = self.monomorphize(value.const_); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index beaf895097842..61397bda546f4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,10 +1,11 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; use rustc_attr_data_structures::InstructionSetAttr; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility}; -use rustc_middle::mir::{InlineAsmOperand, START_BLOCK}; +use rustc_middle::mir::{ConstValue, InlineAsmOperand, START_BLOCK}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::{bug, ty}; +use rustc_middle::{bug, span_bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::BinaryFormat; @@ -52,7 +53,7 @@ pub fn codegen_naked_asm< template_vec.extend(template.iter().cloned()); template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end.into())); - cx.codegen_global_asm(&template_vec, &operands, options, line_spans); + cx.codegen_global_asm(&template_vec, &operands, options, line_spans, instance); } fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>>( @@ -77,14 +78,25 @@ fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndL ty::EarlyBinder::bind(value.ty()), ); - let string = common::asm_const_to_str( - cx.tcx(), - value.span, - const_value, - cx.layout_of(mono_type), - ); - - GlobalAsmOperandRef::Const { string } + let ConstValue::Scalar(scalar) = const_value else { + span_bug!( + value.span, + "expected Scalar for promoted asm const, but got {:#?}", + const_value + ) + }; + match scalar { + Scalar::Int(_) => { + let string = common::asm_const_to_str( + cx.tcx(), + value.span, + const_value, + cx.layout_of(mono_type), + ); + GlobalAsmOperandRef::Interpolate { string } + } + Scalar::Ptr(value, _) => GlobalAsmOperandRef::ConstPointer { value }, + } } InlineAsmOperand::SymFn { value } => { let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index cc7a6a3f19e9e..5d9d76ae4fa65 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -1,5 +1,6 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::def_id::DefId; +use rustc_middle::mir; use rustc_middle::ty::Instance; use rustc_span::Span; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -25,9 +26,18 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { in_value: OperandRef<'tcx, B::Value>, out_place: Option>, }, - Const { + /// Interpolate a string directly into the inline assembly. + /// + /// This is distinct from `Const`, which can reference a const pointer or reference (and thus is + /// a const in Rust/linker sense but not a literal value). + /// + /// We currently use this for constant integers. They could technically use `Const` as well. + Interpolate { string: String, }, + Const { + value: OperandRef<'tcx, B::Value>, + }, SymFn { instance: Instance<'tcx>, }, @@ -41,7 +51,8 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { #[derive(Debug)] pub enum GlobalAsmOperandRef<'tcx> { - Const { string: String }, + Interpolate { string: String }, + ConstPointer { value: mir::interpret::Pointer }, SymFn { instance: Instance<'tcx> }, SymStatic { def_id: DefId }, } @@ -61,12 +72,14 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { } pub trait AsmCodegenMethods<'tcx> { + /// Code generate a global or naked assembly. fn codegen_global_asm( &mut self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, line_spans: &[Span], + instance: Instance<'tcx>, ); /// The mangled name of this instance diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index dcd9e25b2c952..32c24965e1bf6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -154,9 +154,9 @@ pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes { // For backends that support CFI using type membership (i.e., testing whether a given pointer is // associated with a type identifier). pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes { - fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn typeid_metadata(&self, _typeid: String) -> Option { + fn add_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn set_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn typeid_metadata(&self, _typeid: &[u8]) -> Option { None } fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index b767ca9a3c251..c9b7356432da7 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -296,19 +296,22 @@ const_eval_pointer_arithmetic_overflow = overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` const_eval_pointer_out_of_bounds = - {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg -> - [false] {$alloc_size_minus_ptr_offset -> - [0] is at or beyond the end of the allocation of size {$alloc_size -> - [1] 1 byte - *[x] {$alloc_size} bytes + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg -> + [true] points to before the beginning of the allocation + *[false] {$inbounds_size_is_neg -> + [false] {$alloc_size_minus_ptr_offset -> + [0] is at or beyond the end of the allocation of size {$alloc_size -> + [1] 1 byte + *[x] {$alloc_size} bytes + } + [1] is only 1 byte from the end of the allocation + *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + } + *[true] {$ptr_offset_abs -> + [0] is at the beginning of the allocation + *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation } - [1] is only 1 byte from the end of the allocation - *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation - } - *[true] {$ptr_offset_abs -> - [0] is at the beginning of the allocation - *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation - } + } } const_eval_pointer_use_after_free = diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index ad3e02580f338..1503f3bcd990b 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout}; +use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 41fc8d47cd369..11e7706fe6058 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ - self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, - TyAndLayout, + self, FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, + LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; use rustc_middle::{mir, span_bug}; @@ -92,20 +92,6 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } } -impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { - /// This inherent method takes priority over the trait method with the same name in LayoutOf, - /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. - /// See [LayoutOf::layout_of] for the original documentation. - #[inline(always)] - pub fn layout_of( - &self, - ty: Ty<'tcx>, - ) -> as LayoutOfHelpers<'tcx>>::LayoutOfResult { - let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind()); - LayoutOf::layout_of(self, ty) - } -} - impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>; @@ -121,6 +107,43 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { } } +impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// This inherent method takes priority over the trait method with the same name in LayoutOf, + /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. + /// See [LayoutOf::layout_of] for the original documentation. + #[inline(always)] + pub fn layout_of(&self, ty: Ty<'tcx>) -> >::LayoutOfResult { + let _span = enter_trace_span!(M, "InterpCx::layout_of", ty = ?ty.kind()); + LayoutOf::layout_of(self, ty) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_fn_ptr] with a tracing span. + /// See [FnAbiOf::fn_abi_of_fn_ptr] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_fn_ptr( + &self, + sig: ty::PolyFnSig<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_fn_ptr", ?sig, ?extra_args); + FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance] with a tracing span. + /// See [FnAbiOf::fn_abi_of_instance] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_instance( + &self, + instance: ty::Instance<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_instance", ?instance, ?extra_args); + FnAbiOf::fn_abi_of_instance(self, instance, extra_args) + } +} + /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 833fcc3881790..629dcc3523ca0 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -5,7 +5,6 @@ use either::Either; use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_index::IndexSlice; -use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1849038545556..f3ed604210565 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1237,9 +1237,55 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option bool { + let s1 = s1.replace('-', "_"); + let s2 = s2.replace('-', "_"); + s1 == s2 + } + + if let Some(name) = matches.opt_str("o") + && let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o") + { + let filename = suspect.strip_prefix("-").unwrap_or(suspect); + let optgroups = config::rustc_optgroups(); + let fake_args = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"]; + + // Check if provided filename might be confusing in conjunction with `-o` flag, + // i.e. consider `-o{filename}` such as `-optimize` with `filename` being `ptimize`. + // There are high-value confusables, for example: + // - Long name of flags, e.g. `--out-dir` vs `-out-dir` + // - C compiler flag, e.g. `optimize`, `o0`, `o1`, `o2`, `o3`, `ofast`. + // - Codegen flags, e.g. `pt-level` of `-opt-level`. + if optgroups.iter().any(|option| eq_ignore_separators(option.long_name(), filename)) + || config::CG_OPTIONS.iter().any(|option| eq_ignore_separators(option.name(), filename)) + || fake_args.iter().any(|arg| eq_ignore_separators(arg, filename)) + { + early_dcx.early_warn( + "option `-o` has no space between flag name and value, which can be confusing", + ); + early_dcx.early_note(format!( + "output filename `-o {name}` is applied instead of a flag named `o{name}`" + )); + early_dcx.early_help(format!( + "insert a space between `-o` and `{name}` if this is intentional: `-o {name}`" + )); + } + } +} + fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { Input::File(file) => new_parser_from_file(&sess.psess, file, None), diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 85683c1a03ff2..51d6e43ab6720 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -3,8 +3,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, - attr, token, tokenstream, + self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, + UnOp, attr, token, tokenstream, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -766,4 +766,10 @@ impl<'a> ExtCtxt<'a> { span, ) } + + // Builds an attribute fully manually. + pub fn attr_nested(&self, inner: AttrItem, span: Span) -> ast::Attribute { + let g = &self.sess.psess.attr_id_generator; + attr::mk_attr_from_item(g, inner, None, ast::AttrStyle::Outer, span) + } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e985e04ba3307..59b3f0bc5efc6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -377,6 +377,8 @@ declare_features! ( (unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)), /// Allows #[cfg(...)] on inline assembly templates and operands. (unstable, asm_cfg, "1.89.0", Some(140364)), + /// Allows using `const` operands with pointer in inline assembly. + (unstable, asm_const_ptr, "CURRENT_RUSTC_VERSION", Some(128464)), /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), /// Enables experimental register support in inline assembly. diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index bac4d70103c3d..7de323b17007b 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -15,6 +15,10 @@ hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new hir_typeck_as_deref_suggestion = consider using `as_deref` here + +hir_typeck_asm_const_ptr_unstable = + using pointers in asm `const` operand is experimental + hir_typeck_base_expression_double_dot = base expression required after `..` hir_typeck_base_expression_double_dot_add_expr = add a base expression here hir_typeck_base_expression_double_dot_enable_default_field_values = diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index a8bb6956f1016..ac96bde57c891 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -18,6 +18,13 @@ use rustc_span::{Ident, Span, Symbol}; use crate::fluent_generated as fluent; +#[derive(Diagnostic)] +#[diag(hir_typeck_asm_const_ptr_unstable)] +pub(crate) struct AsmConstPtrUnstable { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_typeck_base_expression_double_dot, code = E0797)] pub(crate) struct BaseExpressionDoubleDot { diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index b59c1752c25ad..91423c1acef9e 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -14,7 +14,7 @@ use rustc_target::asm::{ use rustc_trait_selection::infer::InferCtxtExt; use crate::FnCtxt; -use crate::errors::RegisterTypeUnstable; +use crate::errors::{AsmConstPtrUnstable, RegisterTypeUnstable}; pub(crate) struct InlineAsmCtxt<'a, 'tcx> { target_features: &'tcx FxIndexSet, @@ -511,7 +511,36 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { match ty.kind() { ty::Error(_) => {} _ if ty.is_integral() => {} + ty::FnPtr(..) => { + if !self.tcx().features().asm_const_ptr() { + self.tcx() + .sess + .create_feature_err( + AsmConstPtrUnstable { span: op_sp }, + sym::asm_const_ptr, + ) + .emit(); + } + } + ty::RawPtr(pointee, _) | ty::Ref(_, pointee, _) + if self.is_thin_ptr_ty(op_sp, *pointee) => + { + if !self.tcx().features().asm_const_ptr() { + self.tcx() + .sess + .create_feature_err( + AsmConstPtrUnstable { span: op_sp }, + sym::asm_const_ptr, + ) + .emit(); + } + } _ => { + let const_possible_ty = if !self.tcx().features().asm_const_ptr() { + "integer" + } else { + "integer or thin pointer" + }; self.fcx .dcx() .struct_span_err(op_sp, "invalid type for `const` operand") @@ -519,7 +548,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { self.tcx().def_span(anon_const.def_id), format!("is {} `{}`", ty.kind().article(), ty), ) - .with_help("`const` operands must be of an integer type") + .with_help(format!( + "`const` operands must be of an {const_possible_ty} type" + )) .emit(); } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 47ba850d50dd4..5e849597ca66c 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -121,7 +121,7 @@ impl<'tcx> MonoItem<'tcx> { MonoItem::Fn(instance) => tcx.symbol_name(instance), MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)), MonoItem::GlobalAsm(item_id) => { - SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.owner_id)) + tcx.symbol_name(Instance::mono(tcx, item_id.owner_id.to_def_id())) } } } diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index ccf76dc710874..986c001de5e80 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,3 +1,4 @@ +use rustc_attr_data_structures::{AttributeKind, CoverageStatus, find_attr}; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind}; @@ -5,7 +6,6 @@ use rustc_middle::mir::{Body, Statement, StatementKind}; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_span::def_id::LocalDefId; -use rustc_span::sym; use tracing::trace; use crate::coverage::counters::node_flow::make_node_counters; @@ -58,26 +58,20 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// Query implementation for `coverage_attr_on`. fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // Check for annotations directly on this def. - if let Some(attr) = tcx.get_attr(def_id, sym::coverage) { - match attr.meta_item_list().as_deref() { - Some([item]) if item.has_name(sym::off) => return false, - Some([item]) if item.has_name(sym::on) => return true, - Some(_) | None => { - // Other possibilities should have been rejected by `rustc_parse::validate_attr`. - // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880). - tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute"); - } + if let Some(coverage_status) = + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_, status) => status) + { + *coverage_status == CoverageStatus::On + } else { + match tcx.opt_local_parent(def_id) { + // Check the parent def (and so on recursively) until we find an + // enclosing attribute or reach the crate root. + Some(parent) => tcx.coverage_attr_on(parent), + // We reached the crate root without seeing a coverage attribute, so + // allow coverage instrumentation by default. + None => true, } } - - match tcx.opt_local_parent(def_id) { - // Check the parent def (and so on recursively) until we find an - // enclosing attribute or reach the crate root. - Some(parent) => tcx.coverage_attr_on(parent), - // We reached the crate root without seeing a coverage attribute, so - // allow coverage instrumentation by default. - None => true, - } } /// Query implementation for `coverage_ids_info`. diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 91c8e64ce9afe..da64c919d210e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -486,10 +486,18 @@ fn collect_items_rec<'tcx>( if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind { for (op, op_sp) in asm.operands { match *op { - hir::InlineAsmOperand::Const { .. } => { - // Only constants which resolve to a plain integer - // are supported. Therefore the value should not - // depend on any other items. + hir::InlineAsmOperand::Const { anon_const } => { + match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { + Ok(val) => { + collect_const_value(tcx, val, &mut used_items); + } + Err(ErrorHandled::TooGeneric(..)) => { + span_bug!(*op_sp, "asm const cannot be resolved; too generic") + } + Err(ErrorHandled::Reported(..)) => { + continue; + } + } } hir::InlineAsmOperand::SymFn { expr } => { let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 783d79d978ab6..a476f0db37e0d 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -318,6 +318,7 @@ pub fn check_builtin_meta_item( | sym::rustc_layout_scalar_valid_range_end | sym::no_implicit_prelude | sym::automatically_derived + | sym::coverage ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2009ddc1e2d59..810472eb2dedb 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -285,6 +285,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::StdInternalSymbol(attr_span)) => { self.check_rustc_std_internal_symbol(attr_span, span, target) } + &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => { + self.check_coverage(attr_span, span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -294,7 +297,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) } - [sym::coverage, ..] => self.check_coverage(attr, span, target), [sym::no_sanitize, ..] => { self.check_no_sanitize(attr, span, target) } @@ -585,7 +587,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `#[coverage(..)]` is applied to a function/closure/method, /// or to an impl block or module. - fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) { + fn check_coverage(&self, attr_span: Span, target_span: Span, target: Target) { let mut not_fn_impl_mod = None; let mut no_body = None; @@ -608,7 +610,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.dcx().emit_err(errors::CoverageAttributeNotAllowed { - attr_span: attr.span(), + attr_span, not_fn_impl_mod, no_body, help: (), diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a91e2140fd44e..d6215e1de043a 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1708,6 +1708,11 @@ impl RustcOptGroup { OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc), }; } + + /// This is for diagnostics-only. + pub fn long_name(&self) -> &str { + self.long_name + } } pub fn make_opt( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c1b..ea9dedf288fdc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -468,6 +468,7 @@ symbols! { asm, asm_cfg, asm_const, + asm_const_ptr, asm_experimental_arch, asm_experimental_reg, asm_goto, @@ -839,6 +840,7 @@ symbols! { derive, derive_coerce_pointee, derive_const, + derive_const_issue: "118304", derive_default_enum, derive_smart_pointer, destruct, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 12d1de463136a..90965000d6fa6 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -36,6 +36,11 @@ pub(super) fn mangle<'tcx>( debug!(?instance_ty); break; } + DefPathData::GlobalAsm => { + // `global_asm!` doesn't have a type. + instance_ty = tcx.types.unit; + break; + } _ => { // if we're making a symbol for something, there ought // to be a value or type-def or something in there diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index fe0f8e6113ef7..51e653a9ab31e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -867,6 +867,16 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // are effectively living in their parent modules. DefPathData::ForeignMod => return print_prefix(self), + // Global asm are handled similar to shims. + DefPathData::GlobalAsm => { + return self.path_append_ns( + print_prefix, + 'S', + disambiguated_data.disambiguator as u64, + "global_asm", + ); + } + // Uppercase categories are more stable than lowercase ones. DefPathData::TypeNs(_) => 't', DefPathData::ValueNs(_) => 'v', @@ -880,7 +890,6 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // These should never show up as `path_append` arguments. DefPathData::CrateRoot | DefPathData::Use - | DefPathData::GlobalAsm | DefPathData::Impl | DefPathData::MacroNs(_) | DefPathData::LifetimeNs(_) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 16356f749c92b..62203e132b70c 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -374,9 +374,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] { } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl Index for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const Index for [T; N] where - [T]: Index, + [T]: ~const Index, { type Output = <[T] as Index>::Output; @@ -387,9 +388,10 @@ where } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl IndexMut for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const IndexMut for [T; N] where - [T]: IndexMut, + [T]: ~const IndexMut, { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 03b120fbf0c34..6419ae9911359 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -381,7 +381,8 @@ pub struct AssertParamIsEq { /// /// assert_eq!(2.cmp(&1), Ordering::Greater); /// ``` -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)] +#[derive_const(PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] // This is a lang item only so that `BinOp::Cmp` in MIR can return it. // It has no special behavior, but does require that the three variants diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs index a06a5227fe285..7d61c9345ecf8 100644 --- a/library/core/src/cmp/bytewise.rs +++ b/library/core/src/cmp/bytewise.rs @@ -17,11 +17,15 @@ use crate::num::NonZero; /// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct. /// - `>::{eq,ne}` are equivalent to comparing the bytes. #[rustc_specialization_trait] -pub(crate) unsafe trait BytewiseEq: PartialEq + Sized {} +#[const_trait] +pub(crate) unsafe trait BytewiseEq: + ~const PartialEq + Sized +{ +} macro_rules! is_bytewise_comparable { ($($t:ty),+ $(,)?) => {$( - unsafe impl BytewiseEq for $t {} + unsafe impl const BytewiseEq for $t {} )+}; } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 1ece3d9bd5e4c..b11972600fa46 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2208,6 +2208,7 @@ pub const unsafe fn raw_eq(a: &T, b: &T) -> bool; /// [valid]: crate::ptr#safety #[rustc_nounwind] #[rustc_intrinsic] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub const unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; /// See documentation of [`std::hint::black_box`] for details. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2f701171505c7..fedc4dada2037 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -103,6 +103,7 @@ #![feature(cfg_select)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(const_carrying_mul_add)] +#![feature(const_cmp)] #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -146,6 +147,7 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 1b6dbc2f428f7..8ac6ce2242d4e 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1615,7 +1615,7 @@ pub(crate) mod builtin { /// See [the reference] for more info. /// /// [the reference]: ../../../reference/attributes/derive.html - #[unstable(feature = "derive_const", issue = "none")] + #[unstable(feature = "derive_const", issue = "118304")] #[rustc_builtin_macro] pub macro derive_const($item:item) { /* compiler built-in */ diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 11d50e0f89f30..b8900c4113ad3 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -200,9 +200,10 @@ impl UseCloned for NonZero where T: ZeroablePrimitive {} impl Copy for NonZero where T: ZeroablePrimitive {} #[stable(feature = "nonzero", since = "1.28.0")] -impl PartialEq for NonZero +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for NonZero where - T: ZeroablePrimitive + PartialEq, + T: ZeroablePrimitive + ~const PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 55fa91d0b9f49..c460f38bd2e4d 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -94,9 +94,9 @@ macro_rules! sh_impl_signed { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shr((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(-other as u32)) } else { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } } @@ -119,9 +119,9 @@ macro_rules! sh_impl_signed { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shl((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(-other as u32)) } else { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } } @@ -147,7 +147,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, @@ -168,7 +168,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, @@ -1052,39 +1052,3 @@ macro_rules! wrapping_int_impl_unsigned { } wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 } - -mod shift_max { - #![allow(non_upper_case_globals)] - - #[cfg(target_pointer_width = "16")] - mod platform { - pub(crate) const usize: u32 = super::u16; - pub(crate) const isize: u32 = super::i16; - } - - #[cfg(target_pointer_width = "32")] - mod platform { - pub(crate) const usize: u32 = super::u32; - pub(crate) const isize: u32 = super::i32; - } - - #[cfg(target_pointer_width = "64")] - mod platform { - pub(crate) const usize: u32 = super::u64; - pub(crate) const isize: u32 = super::i64; - } - - pub(super) const i8: u32 = (1 << 3) - 1; - pub(super) const i16: u32 = (1 << 4) - 1; - pub(super) const i32: u32 = (1 << 5) - 1; - pub(super) const i64: u32 = (1 << 6) - 1; - pub(super) const i128: u32 = (1 << 7) - 1; - pub(super) use self::platform::isize; - - pub(super) const u8: u32 = i8; - pub(super) const u16: u32 = i16; - pub(super) const u32: u32 = i32; - pub(super) const u64: u32 = i64; - pub(super) const u128: u32 = i128; - pub(super) use self::platform::usize; -} diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 8092fa9eb2fc5..d8489e9a94913 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -55,6 +55,8 @@ #[doc(alias = "]")] #[doc(alias = "[")] #[doc(alias = "[]")] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -165,7 +167,9 @@ see chapter in The Book : Index { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[const_trait] +pub trait IndexMut: ~const Index { /// Performs the mutable indexing (`container[index]`) operation. /// /// # Panics diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9f432758a66f6..da6e311ff5e1b 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2243,7 +2243,8 @@ impl<'a, T> From<&'a mut Option> for Option<&'a mut T> { #[stable(feature = "rust1", since = "1.0.0")] impl crate::marker::StructuralPartialEq for Option {} #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Option { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for Option { #[inline] fn eq(&self, other: &Self) -> bool { // Spelling out the cases explicitly optimizes better than diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 7b9e04920d51d..a4be66b90cab3 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -80,7 +80,7 @@ pub use crate::macros::builtin::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; -#[unstable(feature = "derive_const", issue = "none")] +#[unstable(feature = "derive_const", issue = "118304")] pub use crate::macros::builtin::derive_const; #[unstable( diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 27b0c6830db61..2ad520b7ead72 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1524,10 +1524,11 @@ impl *const [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + pub const unsafe fn get_unchecked(self, index: I) -> *const I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked(self) } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 73efdf0445412..579e2461103d8 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1881,10 +1881,11 @@ impl *mut [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + pub const unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked_mut(self) } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index c4ca29a367971..62da6567cca75 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1597,10 +1597,11 @@ impl NonNull<[T]> { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + pub const unsafe fn get_unchecked_mut(self, index: I) -> NonNull where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. // As a consequence, the resulting pointer cannot be null. diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 2276112a27bb3..5cd7956291ca2 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -186,14 +186,17 @@ impl IntoBounds for Range { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::Range { #[inline] fn from(value: Range) -> Self { Self { start: value.start, end: value.end } } } + #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for Range { #[inline] fn from(value: legacy::Range) -> Self { Self { start: value.start, end: value.end } @@ -362,7 +365,8 @@ impl IntoBounds for RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeInclusive { #[inline] fn from(value: RangeInclusive) -> Self { Self::new(value.start, value.end) @@ -506,14 +510,16 @@ impl IntoBounds for RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeFrom { #[inline] fn from(value: RangeFrom) -> Self { Self { start: value.start } } } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for RangeFrom { #[inline] fn from(value: legacy::RangeFrom) -> Self { Self { start: value.start } diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 5ce72b46eee36..1eda8bc1bec40 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -8,9 +8,10 @@ use crate::num::NonZero; use crate::ops::ControlFlow; #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[U]> for [T] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq<[U]> for [T] where - T: PartialEq, + T: ~const PartialEq, { fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) @@ -94,6 +95,8 @@ impl PartialOrd for [T] { #[doc(hidden)] // intermediate trait for specialization of slice's PartialEq +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] trait SlicePartialEq { fn equal(&self, other: &[B]) -> bool; @@ -103,9 +106,10 @@ trait SlicePartialEq { } // Generic slice equality -impl SlicePartialEq for [A] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SlicePartialEq for [A] where - A: PartialEq, + A: ~const PartialEq, { default fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { @@ -115,11 +119,14 @@ where // Implemented as explicit indexing rather // than zipped iterators for performance reasons. // See PR https://github.com/rust-lang/rust/pull/116846 - for idx in 0..self.len() { + // FIXME(const_hack): make this a `for idx in 0..self.len()` loop. + let mut idx = 0; + while idx < self.len() { // bound checks are optimized away if self[idx] != other[idx] { return false; } + idx += 1; } true @@ -128,9 +135,10 @@ where // When each element can be compared byte-wise, we can compare all the bytes // from the whole size in one call to the intrinsics. -impl SlicePartialEq for [A] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const SlicePartialEq for [A] where - A: BytewiseEq, + A: ~const BytewiseEq, { fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index f725c3fdd94cc..322b3580eded2 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { type Output = I::Output; @@ -19,9 +20,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { #[inline(always)] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -158,6 +160,8 @@ mod private_slice_index { message = "the type `{T}` cannot be indexed by `{Self}`", label = "slice indices are of type `usize` or ranges of `usize`" )] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -208,7 +212,8 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The methods `index` and `index_mut` panic if the index is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -278,7 +283,8 @@ unsafe impl SliceIndex<[T]> for usize { /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here /// than there are for a general `Range` (which might be `100..3`). -unsafe impl SliceIndex<[T]> for ops::IndexRange { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::IndexRange { type Output = [T]; #[inline] @@ -354,7 +360,8 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -453,7 +460,8 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::Range { type Output = [T]; #[inline] @@ -491,7 +499,8 @@ unsafe impl SliceIndex<[T]> for range::Range { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -529,7 +538,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeTo { /// The methods `index` and `index_mut` panic if the start of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -574,7 +584,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeFrom { type Output = [T]; #[inline] @@ -611,7 +622,8 @@ unsafe impl SliceIndex<[T]> for range::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -650,7 +662,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFull { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -693,7 +706,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeInclusive { type Output = [T]; #[inline] @@ -731,7 +745,8 @@ unsafe impl SliceIndex<[T]> for range::RangeInclusive { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index abcba5a621e23..32419024db953 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -568,9 +568,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get(&self, index: I) -> Option<&I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get(self) } @@ -594,9 +595,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get_mut(self) } @@ -633,9 +635,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked(&self, index: I) -> &I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; // the slice is dereferenceable because `self` is a safe reference. @@ -677,9 +680,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; // the slice is dereferenceable because `self` is a safe reference. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 2e26cc871dfe4..18a516c0f608c 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -589,8 +589,9 @@ impl str { /// assert!(v.get(..42).is_none()); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get>(&self, i: I) -> Option<&I::Output> { + pub const fn get>(&self, i: I) -> Option<&I::Output> { i.get(self) } @@ -621,8 +622,9 @@ impl str { /// assert_eq!("HEllo", v); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + pub const fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { i.get_mut(self) } diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index b9559c8317133..d0f2b9226bf6d 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -23,7 +23,8 @@ impl Ord for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for str { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq for str { #[inline] fn eq(&self, other: &str) -> bool { self.as_bytes() == other.as_bytes() @@ -49,9 +50,10 @@ impl PartialOrd for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for str where - I: SliceIndex, + I: ~const SliceIndex, { type Output = I::Output; @@ -62,9 +64,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for str where - I: SliceIndex, + I: ~const SliceIndex, { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -92,7 +95,8 @@ const fn str_index_overflow_fail() -> ! { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFull { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -156,7 +160,8 @@ unsafe impl SliceIndex for ops::RangeFull { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -260,7 +265,8 @@ unsafe impl SliceIndex for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -431,7 +437,8 @@ unsafe impl SliceIndex for (ops::Bound, ops::Bound) { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeTo { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -499,7 +506,8 @@ unsafe impl SliceIndex for ops::RangeTo { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -554,7 +562,8 @@ unsafe impl SliceIndex for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -625,7 +634,8 @@ unsafe impl SliceIndex for range::RangeFrom { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -662,7 +672,8 @@ unsafe impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -713,7 +724,8 @@ unsafe impl SliceIndex for range::RangeInclusive { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 38df09a91c103..36d6a20a94427 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,9 +1,7 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -use core::ops::{Add, Div, Mul, Sub}; use std::f128::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -38,160 +36,9 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; /// Second pattern over the mantissa const NAN_MASK2: u128 = 0x00005555555555555555555555555555; -#[test] -fn test_num_f128() { - // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` - // function is available on all platforms. - let ten = 10f128; - let two = 2f128; - assert_biteq!(ten.add(two), ten + two); - assert_biteq!(ten.sub(two), ten - two); - assert_biteq!(ten.mul(two), ten * two); - assert_biteq!(ten.div(two), ten / two); - #[cfg(any(miri, target_has_reliable_f128_math))] - assert_biteq!(core::ops::Rem::rem(ten, two), ten % two); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f128 = f128::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f128 = 0.0f128; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f128 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f128 = 1.0f128; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f128.is_nan()); - assert!(!5.3f128.is_nan()); - assert!(!(-10.732f128).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f128.is_infinite()); - assert!(!42.8f128.is_infinite()); - assert!(!(-109.2f128).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f128.is_finite()); - assert!(42.8f128.is_finite()); - assert!((-109.2f128).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f128.is_normal()); - assert!(1e-4931f128.is_normal()); - assert!(!1e-4932f128.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f128.classify(), Fp::Normal); - assert_eq!(1e-4931f128.classify(), Fp::Normal); - assert_eq!(1e-4932f128.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index f6749d796cca9..351c008a37bab 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f16)] use std::f16::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -43,151 +42,9 @@ const NAN_MASK1: u16 = 0x02aa; /// Second pattern over the mantissa const NAN_MASK2: u16 = 0x0155; -#[test] -fn test_num_f16() { - super::test_num(10f16, 2f16); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f16 = f16::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f16 = 0.0f16; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f16 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f16 = 1.0f16; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f16.is_nan()); - assert!(!5.3f16.is_nan()); - assert!(!(-10.732f16).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f16.is_infinite()); - assert!(!42.8f16.is_infinite()); - assert!(!(-109.2f16).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f16.is_finite()); - assert!(42.8f16.is_finite()); - assert!((-109.2f16).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f16.is_normal()); - assert!(1e-4f16.is_normal()); - assert!(!1e-5f16.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f16.classify(), Fp::Normal); - assert_eq!(1e-4f16.classify(), Fp::Normal); - assert_eq!(1e-5f16.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index f5d5723fea455..267b0e4e29434 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,6 +1,5 @@ use core::f32; use core::f32::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -30,148 +29,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_num_f32() { - super::test_num(10f32, 2f32); -} - -#[test] -fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f32 = 0.0f32; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f32 = 1.0f32; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 34af87c241e91..735b7a7651519 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,6 +1,5 @@ use core::f64; use core::f64::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -25,147 +24,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_num_f64() { - super::test_num(10f64, 2f64); -} - -#[test] -fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f64 = 0.0f64; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f64 = 1.0f64; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 36743a7d6df9e..43431bba6954b 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,28 +1,40 @@ -use std::fmt; use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Set the default tolerance for float comparison based on the type. -trait Approx { - const LIM: Self; +trait TestableFloat { + /// Set the default tolerance for float comparison based on the type. + const APPROX: Self; + const MIN_POSITIVE_NORMAL: Self; + const MAX_SUBNORMAL: Self; } -impl Approx for f16 { - const LIM: Self = 1e-3; +impl TestableFloat for f16 { + const APPROX: Self = 1e-3; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f32 { - const LIM: Self = 1e-6; + +impl TestableFloat for f32 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f64 { - const LIM: Self = 1e-6; + +impl TestableFloat for f64 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f128 { - const LIM: Self = 1e-9; + +impl TestableFloat for f128 { + const APPROX: Self = 1e-9; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } /// Determine the tolerance for values of the argument type. -const fn lim_for_ty(_x: T) -> T { - T::LIM +const fn lim_for_ty(_x: T) -> T { + T::APPROX } // We have runtime ("rt") and const versions of these macros. @@ -187,9 +199,11 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { #[allow(unused)] - use super::Approx; + use super::TestableFloat; #[allow(unused)] use std::num::FpCategory as Fp; + #[allow(unused)] + use std::ops::{Add, Div, Mul, Rem, Sub}; // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] use $crate::floats::{ @@ -229,30 +243,42 @@ macro_rules! float_test { }; } -/// Helper function for testing numeric operations -pub fn test_num(ten: T, two: T) -where - T: PartialEq - + Add - + Sub - + Mul - + Div - + Rem - + fmt::Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} - mod f128; mod f16; mod f32; mod f64; +float_test! { + name: num, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.add(two), ten + two); + assert_biteq!(ten.sub(two), ten - two); + assert_biteq!(ten.mul(two), ten * two); + assert_biteq!(ten.div(two), ten / two); + } +} + +// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on +// all platforms. +float_test! { + name: num_rem, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.rem(two), ten % two); + } +} + float_test! { name: nan, attrs: { @@ -273,6 +299,213 @@ float_test! { } } +float_test! { + name: infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let inf: Float = Float::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert!(matches!(inf.classify(), Fp::Infinite)); + } +} + +float_test! { + name: neg_infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_inf: Float = Float::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + } +} + +float_test! { + name: zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let zero: Float = 0.0; + assert_biteq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert!(matches!(zero.classify(), Fp::Zero)); + } +} + +float_test! { + name: neg_zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_zero: Float = -0.0; + assert!(0.0 == neg_zero); + assert_biteq!(-0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + } +} + +float_test! { + name: one, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let one: Float = 1.0; + assert_biteq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert!(matches!(one.classify(), Fp::Normal)); + } +} + +float_test! { + name: is_nan, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 5.3; + let neg: Float = -10.732; + assert!(nan.is_nan()); + assert!(!zero.is_nan()); + assert!(!pos.is_nan()); + assert!(!neg.is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); + } +} + +float_test! { + name: is_infinite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!zero.is_infinite()); + assert!(!pos.is_infinite()); + assert!(!neg.is_infinite()); + } +} + +float_test! { + name: is_finite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(zero.is_finite()); + assert!(pos.is_finite()); + assert!(neg.is_finite()); + } +} + +float_test! { + name: is_normal, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one : Float = 1.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(one.is_normal()); + assert!(Float::MIN_POSITIVE_NORMAL.is_normal()); + assert!(!Float::MAX_SUBNORMAL.is_normal()); + } +} + +float_test! { + name: classify, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one: Float = 1.0; + assert!(matches!(nan.classify(), Fp::Nan)); + assert!(matches!(inf.classify(), Fp::Infinite)); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + assert!(matches!(zero.classify(), Fp::Zero)); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + assert!(matches!(one.classify(), Fp::Normal)); + assert!(matches!(Float::MIN_POSITIVE_NORMAL.classify(), Fp::Normal)); + assert!(matches!(Float::MAX_SUBNORMAL.classify(), Fp::Subnormal)); + } +} + float_test! { name: min, attrs: { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index fdef736c0c0f7..e2249bd7f6a11 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_float_round_methods)] +#![feature(const_ops)] #![feature(const_ref_cell)] #![feature(const_trait_impl)] #![feature(core_float_math)] diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 69f0335315356..70c1113155656 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -67,7 +67,7 @@ pub use core::prelude::v1::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; -#[unstable(feature = "derive_const", issue = "none")] +#[unstable(feature = "derive_const", issue = "118304")] pub use core::prelude::v1::derive_const; // Do not `doc(no_inline)` either. diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index c150dc16b0729..f2283f0902b07 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -13,7 +13,7 @@ use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout}; use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy}; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs new file mode 100644 index 0000000000000..107a3db91d857 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs @@ -0,0 +1,6 @@ +fn main() { + let v: Vec = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; //~ ERROR: before the beginning of the allocation + panic!("this should never print: {}", x); +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr new file mode 100644 index 0000000000000..5c37caa1ebf06 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC-0x5 which points to before the beginning of the allocation + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: ALLOC was allocated here: + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let v: Vec = vec![1, 2]; + | ^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +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/intrinsics/ptr_offset_out_of_bounds_neg2.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs new file mode 100644 index 0000000000000..0085e2af36734 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs @@ -0,0 +1,6 @@ +fn main() { + let v = [0i8; 4]; + let x = &v as *const i8; + let x = unsafe { x.wrapping_offset(-1).offset(-1) }; //~ERROR: before the beginning of the allocation + panic!("this should never print: {:?}", x); +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr new file mode 100644 index 0000000000000..495aaf8d40eef --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC-0x1 which points to before the beginning of the allocation + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let x = unsafe { x.wrapping_offset(-1).offset(-1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: ALLOC was allocated here: + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let v = [0i8; 4]; + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.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/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index bda08423487b5..b9741431b5034 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -335,7 +335,9 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { std::process::exit(code); } else { println!("died due to signal {}", code); - std::process::exit(3); + // Behave like bash and other tools and exit with 128 + the signal + // number. That way we can avoid special case code in other places. + std::process::exit(128 + code); } } diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 050ddf47baefa..27798d6aeb0b3 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -885,9 +885,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.51" +version = "0.4.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328" +checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 69c0cfaf5c99d..c7c6e39f15778 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.51" +version = "0.4.52" default-features = false features = ["search"] diff --git a/tests/assembly/asm/global_asm.rs b/tests/assembly/asm/global_asm.rs index 8a4bf98c7450b..deb8d72f076b5 100644 --- a/tests/assembly/asm/global_asm.rs +++ b/tests/assembly/asm/global_asm.rs @@ -5,6 +5,7 @@ //@ compile-flags: -C symbol-mangling-version=v0 #![crate_type = "rlib"] +#![feature(asm_const_ptr)] use std::arch::global_asm; @@ -26,6 +27,10 @@ global_asm!("call {}", sym my_func); global_asm!("lea rax, [rip + {}]", sym MY_STATIC); // CHECK: call _RNvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_10global_asm6foobar global_asm!("call {}", sym foobar); +// CHECK: lea rax, [rip + _RNSC[[CRATE_IDENT]]_10global_asms4_10global_asm.0] +global_asm!("lea rax, [rip + {}]", const &1); +// CHECK: lea rax, [rip + _RNSC[[CRATE_IDENT]]_10global_asms5_10global_asm.0+4] +global_asm!("lea rax, [rip + {}]", const &[1; 2][1]); // CHECK: _RNvC[[CRATE_IDENT]]_10global_asm6foobar: fn foobar() { loop {} diff --git a/tests/assembly/asm/x86-types.rs b/tests/assembly/asm/x86-types.rs index 6120ed0d53275..921dfc69b646a 100644 --- a/tests/assembly/asm/x86-types.rs +++ b/tests/assembly/asm/x86-types.rs @@ -9,7 +9,7 @@ //@ compile-flags: -C target-feature=+avx512bw //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, repr_simd, f16, f128)] +#![feature(no_core, repr_simd, f16, f128, asm_const_ptr)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -92,6 +92,18 @@ pub unsafe fn sym_fn() { asm!("call {}", sym extern_func); } +// NOTE: this only works for x64, as this test is compiled with PIC, +// and on x86 PIC symbol can't be constant. +// x86_64-LABEL: const_ptr: +// x86_64: #APP +// x86_64: mov al, byte ptr [{{.*}}anon{{.*}}] +// x86_64: #NO_APP +#[cfg(x86_64)] +#[no_mangle] +pub unsafe fn const_ptr() { + asm!("mov al, byte ptr [{}]", const &1); +} + // CHECK-LABEL: sym_static: // CHECK: #APP // CHECK: mov al, byte ptr [extern_static] diff --git a/tests/run-make/option-output-no-space/main.rs b/tests/run-make/option-output-no-space/main.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/tests/run-make/option-output-no-space/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/option-output-no-space/rmake.rs b/tests/run-make/option-output-no-space/rmake.rs new file mode 100644 index 0000000000000..6f54510650a66 --- /dev/null +++ b/tests/run-make/option-output-no-space/rmake.rs @@ -0,0 +1,93 @@ +// This test is to check if the warning is emitted when no space +// between `-o` and arg is applied, see issue #142812 +use run_make_support::rustc; + +fn main() { + // test fake args + rustc() + .input("main.rs") + .arg("-optimize") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o ptimize` is applied instead of a flag named `optimize`", + ); + rustc() + .input("main.rs") + .arg("-o0") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o 0` is applied instead of a flag named `o0`", + ); + rustc().input("main.rs").arg("-o1").run(); + // test real args by iter optgroups + rustc() + .input("main.rs") + .arg("-out-dir") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o ut-dir` is applied instead of a flag named `out-dir`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `ut-dir` if this is intentional: `-o ut-dir`", + ); + // test real args by iter CG_OPTIONS + rustc() + .input("main.rs") + .arg("-opt_level") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o pt_level` is applied instead of a flag named `opt_level`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `pt_level` if this is intentional: `-o pt_level`" + ); + // separater in-sensitive + rustc() + .input("main.rs") + .arg("-opt-level") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o pt-level` is applied instead of a flag named `opt-level`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `pt-level` if this is intentional: `-o pt-level`" + ); + rustc() + .input("main.rs") + .arg("-overflow-checks") + .run() + .assert_stderr_contains( + "warning: option `-o` has no space between flag name and value, which can be confusing", + ) + .assert_stderr_contains( + "note: output filename `-o verflow-checks` \ + is applied instead of a flag named `overflow-checks`", + ) + .assert_stderr_contains( + "help: insert a space between `-o` and `verflow-checks` \ + if this is intentional: `-o verflow-checks`", + ); + + // No warning for Z_OPTIONS + rustc().input("main.rs").arg("-oom").run().assert_stderr_equals(""); + + // test no warning when there is space between `-o` and arg + rustc().input("main.rs").arg("-o").arg("ptimize").run().assert_stderr_equals(""); + rustc().input("main.rs").arg("--out-dir").arg("xxx").run().assert_stderr_equals(""); + rustc().input("main.rs").arg("-o").arg("out-dir").run().assert_stderr_equals(""); +} diff --git a/tests/ui/asm/const-refs-to-static.rs b/tests/ui/asm/const-refs-to-static.rs index ce2c5b3246ec8..8058d70550aba 100644 --- a/tests/ui/asm/const-refs-to-static.rs +++ b/tests/ui/asm/const-refs-to-static.rs @@ -1,19 +1,20 @@ //@ needs-asm-support //@ ignore-nvptx64 //@ ignore-spirv +//@ build-pass + +#![feature(asm_const_ptr)] use std::arch::{asm, global_asm}; use std::ptr::addr_of; static FOO: u8 = 42; -global_asm!("{}", const addr_of!(FOO)); -//~^ ERROR invalid type for `const` operand +global_asm!("/* {} */", const addr_of!(FOO)); #[no_mangle] fn inline() { - unsafe { asm!("{}", const addr_of!(FOO)) }; - //~^ ERROR invalid type for `const` operand + unsafe { asm!("/* {} */", const addr_of!(FOO)) }; } fn main() {} diff --git a/tests/ui/asm/const-refs-to-static.stderr b/tests/ui/asm/const-refs-to-static.stderr deleted file mode 100644 index 10e1ca5bd6068..0000000000000 --- a/tests/ui/asm/const-refs-to-static.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: invalid type for `const` operand - --> $DIR/const-refs-to-static.rs:10:19 - | -LL | global_asm!("{}", const addr_of!(FOO)); - | ^^^^^^------------- - | | - | is a `*const u8` - | - = help: `const` operands must be of an integer type - -error: invalid type for `const` operand - --> $DIR/const-refs-to-static.rs:15:25 - | -LL | unsafe { asm!("{}", const addr_of!(FOO)) }; - | ^^^^^^------------- - | | - | is a `*const u8` - | - = help: `const` operands must be of an integer type - -error: aborting due to 2 previous errors - diff --git a/tests/ui/asm/invalid-const-operand.rs b/tests/ui/asm/invalid-const-operand.rs index bbf4001752a4b..218b49ecb8e1e 100644 --- a/tests/ui/asm/invalid-const-operand.rs +++ b/tests/ui/asm/invalid-const-operand.rs @@ -2,6 +2,8 @@ //@ ignore-nvptx64 //@ ignore-spirv +#![feature(asm_const_ptr)] + use std::arch::{asm, global_asm}; // Const operands must be integers and must be constants. @@ -12,11 +14,10 @@ global_asm!("{}", const 0i128); global_asm!("{}", const 0f32); //~^ ERROR invalid type for `const` operand global_asm!("{}", const 0 as *mut u8); -//~^ ERROR invalid type for `const` operand fn test1() { unsafe { - // Const operands must be integers and must be constants. + // Const operands must be integers or thin pointers asm!("{}", const 0); asm!("{}", const 0i32); @@ -24,8 +25,12 @@ fn test1() { asm!("{}", const 0f32); //~^ ERROR invalid type for `const` operand asm!("{}", const 0 as *mut u8); - //~^ ERROR invalid type for `const` operand asm!("{}", const &0); + asm!("{}", const b"Foo".as_slice()); + //~^ ERROR invalid type for `const` operand + + asm!("{}", const test1 as fn()); + asm!("{}", const test1); //~^ ERROR invalid type for `const` operand } } diff --git a/tests/ui/asm/invalid-const-operand.stderr b/tests/ui/asm/invalid-const-operand.stderr index 01aa843c6fb19..c6b492788b0dc 100644 --- a/tests/ui/asm/invalid-const-operand.stderr +++ b/tests/ui/asm/invalid-const-operand.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/invalid-const-operand.rs:44:26 + --> $DIR/invalid-const-operand.rs:49:26 | LL | asm!("{}", const x); | ^ non-constant value @@ -11,7 +11,7 @@ LL + const x: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/invalid-const-operand.rs:47:36 + --> $DIR/invalid-const-operand.rs:52:36 | LL | asm!("{}", const const_foo(x)); | ^ non-constant value @@ -23,7 +23,7 @@ LL + const x: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/invalid-const-operand.rs:50:36 + --> $DIR/invalid-const-operand.rs:55:36 | LL | asm!("{}", const const_bar(x)); | ^ non-constant value @@ -35,55 +35,45 @@ LL + const x: /* Type */ = 0; | error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:12:19 + --> $DIR/invalid-const-operand.rs:14:19 | LL | global_asm!("{}", const 0f32); | ^^^^^^---- | | | is an `f32` | - = help: `const` operands must be of an integer type - -error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:14:19 - | -LL | global_asm!("{}", const 0 as *mut u8); - | ^^^^^^------------ - | | - | is a `*mut u8` - | - = help: `const` operands must be of an integer type + = help: `const` operands must be of an integer or thin pointer type error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:24:20 + --> $DIR/invalid-const-operand.rs:25:20 | LL | asm!("{}", const 0f32); | ^^^^^^---- | | | is an `f32` | - = help: `const` operands must be of an integer type + = help: `const` operands must be of an integer or thin pointer type error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:26:20 + --> $DIR/invalid-const-operand.rs:29:20 | -LL | asm!("{}", const 0 as *mut u8); - | ^^^^^^------------ +LL | asm!("{}", const b"Foo".as_slice()); + | ^^^^^^----------------- | | - | is a `*mut u8` + | is a `&[u8]` | - = help: `const` operands must be of an integer type + = help: `const` operands must be of an integer or thin pointer type error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:28:20 + --> $DIR/invalid-const-operand.rs:33:20 | -LL | asm!("{}", const &0); - | ^^^^^^-- +LL | asm!("{}", const test1); + | ^^^^^^----- | | - | is a `&i32` + | is a `fn() {test1}` | - = help: `const` operands must be of an integer type + = help: `const` operands must be of an integer or thin pointer type -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 56f2be353e768..0d0c338d30269 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -37,19 +37,6 @@ error: malformed `crate_name` attribute input LL | #[crate_name] | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` -error: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:90:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL | #[coverage(off)] - | +++++ -LL | #[coverage(on)] - | ++++ - error: malformed `no_sanitize` attribute input --> $DIR/malformed-attrs.rs:92:1 | @@ -460,6 +447,19 @@ error[E0539]: malformed `link_section` attribute input LL | #[link_section] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` +error[E0539]: malformed `coverage` attribute input + --> $DIR/malformed-attrs.rs:90:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[coverage(off)] + | +++++ +LL | #[coverage(on)] + | ++++ + error[E0565]: malformed `no_implicit_prelude` attribute input --> $DIR/malformed-attrs.rs:97:1 | diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs index 0bc8585a4eed1..7e3df92a2bf5a 100644 --- a/tests/ui/consts/const-compare-bytes-ub.rs +++ b/tests/ui/consts/const-compare-bytes-ub.rs @@ -1,6 +1,6 @@ //@ check-fail -#![feature(core_intrinsics)] +#![feature(core_intrinsics, const_cmp)] use std::intrinsics::compare_bytes; use std::mem::MaybeUninit; diff --git a/tests/ui/consts/const-compare-bytes.rs b/tests/ui/consts/const-compare-bytes.rs index cd5cdfd0400ec..9563375555cfd 100644 --- a/tests/ui/consts/const-compare-bytes.rs +++ b/tests/ui/consts/const-compare-bytes.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(core_intrinsics)] +#![feature(core_intrinsics, const_cmp)] use std::intrinsics::compare_bytes; fn main() { diff --git a/tests/ui/consts/const-eval/auxiliary/stability.rs b/tests/ui/consts/const-eval/auxiliary/stability.rs index e615955186020..48ced3bc51e62 100644 --- a/tests/ui/consts/const-eval/auxiliary/stability.rs +++ b/tests/ui/consts/const-eval/auxiliary/stability.rs @@ -1,10 +1,11 @@ // Crate that exports a const fn. Used for testing cross-crate. -#![crate_type="rlib"] +#![crate_type = "rlib"] #![stable(feature = "rust1", since = "1.0.0")] - #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature="foo", issue = "none")] -pub const fn foo() -> u32 { 42 } +#[rustc_const_unstable(feature = "foo", issue = "none")] +pub const fn foo() -> u32 { + 42 +} diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs index e805ac01c9d06..ad2b49e60498d 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs @@ -1,9 +1,10 @@ -//@ known-bug: #110395 +#![feature(const_index, const_trait_impl)] const A: [(); 5] = [(), (), (), (), ()]; // Since the indexing is on a ZST, the addresses are all fine, // but we should still catch the bad range. const B: &[()] = unsafe { A.get_unchecked(3..1) }; +//~^ ERROR: slice::get_unchecked requires that the range is within the slice fn main() {} diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr index 6e428079afe8e..88ea310f19c68 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr @@ -1,11 +1,11 @@ -error[E0015]: cannot call non-const method `core::slice::::get_unchecked::>` in constants - --> $DIR/ub-slice-get-unchecked.rs:7:29 +error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the range is within the slice + + This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. + --> $DIR/ub-slice-get-unchecked.rs:7:27 | LL | const B: &[()] = unsafe { A.get_unchecked(3..1) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `B` failed here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 87c8b04452bac..22791e7d15e5d 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -7,7 +7,9 @@ struct Foo<'a> { impl<'a> Foo<'a> { const fn spam(&mut self, baz: &mut Vec) { self.bar[0] = baz.len(); - //~^ ERROR: cannot call + //~^ 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 63a86b456332f..608ce0cfef012 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,13 +1,24 @@ -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-94675.rs:9:17 +error[E0277]: the trait bound `Vec: [const] Index<_>` is not satisfied + --> $DIR/issue-94675.rs:9:9 | LL | self.bar[0] = baz.len(); - | ^^^ + | ^^^^^^^^^^^ + +error[E0277]: the trait bound `Vec: [const] IndexMut` is not satisfied + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ + +error[E0277]: the trait bound `Vec: [const] Index` is not satisfied + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ | -note: impl defined here, but it is not `const` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +note: required by a bound in `std::ops::IndexMut::index_mut` + --> $SRC_DIR/core/src/ops/index.rs:LL:COL -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index 8c52586c485ff..98a50156a9487 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -5,17 +5,17 @@ use std::ptr; //@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes" -pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR -pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR -pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR +pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR: is at the beginning of the allocation +pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR: only 1 byte from the end of the allocation +pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR: only 100 bytes from the end of the allocation -pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR -pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR +pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR: does not fit in an `isize` +pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR: does not fit in an `isize` pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~ ERROR pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~ ERROR -pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR +pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR: before the beginning of the allocation -pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR +pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR: at or beyond the end of the allocation pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; //~ ERROR // Make sure that we don't panic when computing abs(offset*size_of::()) diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 255583ce91c58..d92ca09223de7 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -40,11 +40,11 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ADDRESS_SPACE` failed here -error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which points to before the beginning of the allocation --> $DIR/offset_ub.rs:16:49 | -LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here +LL | ...*const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes --> $DIR/offset_ub.rs:18:50 diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index fa500b542097d..927f61da08db8 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -1,23 +1,59 @@ -error: malformed `coverage` attribute input +error: expected identifier, found `,` + --> $DIR/bad-syntax.rs:44:12 + | +LL | #[coverage(,off)] + | ^ expected identifier + | +help: remove this comma + | +LL - #[coverage(,off)] +LL + #[coverage(off)] + | + +error: multiple `coverage` attributes + --> $DIR/bad-syntax.rs:9:1 + | +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/bad-syntax.rs:10:1 + | +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ + +error: multiple `coverage` attributes + --> $DIR/bad-syntax.rs:13:1 + | +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/bad-syntax.rs:14:1 + | +LL | #[coverage(on)] + | ^^^^^^^^^^^^^^^ + +error[E0539]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:17:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:20:1 | LL | #[coverage = true] - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = true] LL + #[coverage(off)] @@ -26,26 +62,30 @@ LL - #[coverage = true] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0805]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:23:1 | LL | #[coverage()] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^--^ + | | + | expected a single argument here | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++ LL | #[coverage(on)] | ++ -error: malformed `coverage` attribute input +error[E0805]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:26:1 | LL | #[coverage(off, off)] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^----------^ + | | + | expected a single argument here | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(off, off)] LL + #[coverage(off)] @@ -54,13 +94,15 @@ LL - #[coverage(off, off)] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0805]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:29:1 | LL | #[coverage(off, on)] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^---------^ + | | + | expected a single argument here | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(off, on)] LL + #[coverage(off)] @@ -69,13 +111,15 @@ LL - #[coverage(off, on)] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:32:1 | LL | #[coverage(bogus)] - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^-----^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(bogus)] LL + #[coverage(off)] @@ -84,13 +128,15 @@ LL - #[coverage(bogus)] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0805]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:35:1 | LL | #[coverage(bogus, off)] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^------------^ + | | + | expected a single argument here | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(bogus, off)] LL + #[coverage(off)] @@ -99,13 +145,15 @@ LL - #[coverage(bogus, off)] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0805]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:38:1 | LL | #[coverage(off, bogus)] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^------------^ + | | + | expected a single argument here | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(off, bogus)] LL + #[coverage(off)] @@ -114,41 +162,7 @@ LL - #[coverage(off, bogus)] LL + #[coverage(on)] | -error: expected identifier, found `,` - --> $DIR/bad-syntax.rs:44:12 - | -LL | #[coverage(,off)] - | ^ expected identifier - | -help: remove this comma - | -LL - #[coverage(,off)] -LL + #[coverage(off)] - | - -error: multiple `coverage` attributes - --> $DIR/bad-syntax.rs:9:1 - | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/bad-syntax.rs:10:1 - | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ - -error: multiple `coverage` attributes - --> $DIR/bad-syntax.rs:13:1 - | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/bad-syntax.rs:14:1 - | -LL | #[coverage(on)] - | ^^^^^^^^^^^^^^^ - error: aborting due to 11 previous errors +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs index ffd9afe2ce186..8171dbbf69278 100644 --- a/tests/ui/coverage-attr/name-value.rs +++ b/tests/ui/coverage-attr/name-value.rs @@ -20,7 +20,6 @@ mod my_mod_inner { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] struct MyStruct; #[coverage = "off"] @@ -28,22 +27,18 @@ struct MyStruct; impl MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 7; } #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] trait MyTrait { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32; #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T; } @@ -52,12 +47,10 @@ trait MyTrait { impl MyTrait for MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 8; #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T = (); } diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr index f24db78415e39..a838ec5df8ead 100644 --- a/tests/ui/coverage-attr/name-value.stderr +++ b/tests/ui/coverage-attr/name-value.stderr @@ -1,10 +1,10 @@ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:12:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -13,28 +13,28 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:17:5 | LL | #![coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #![coverage = "off"] -LL + #![coverage(off)] +LL + #[coverage(off)] | LL - #![coverage = "off"] -LL + #![coverage(on)] +LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:21:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -43,13 +43,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:26:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:25:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -58,13 +58,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:29:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:28:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -73,13 +73,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:35:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:33:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -88,13 +88,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:39:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:36:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -103,13 +103,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:44:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:40:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -118,13 +118,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:50:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:45:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -133,13 +133,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:53:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:48:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -148,13 +148,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:58:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:52:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -163,13 +163,13 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: malformed `coverage` attribute input - --> $DIR/name-value.rs:64:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/name-value.rs:57:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage = "off"] LL + #[coverage(off)] @@ -178,87 +178,6 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:21:1 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | struct MyStruct; - | ---------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:35:1 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | / trait MyTrait { -LL | | #[coverage = "off"] -... | -LL | | type T; -LL | | } - | |_- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:39:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | const X: u32; - | ------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:44:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | type T; - | ------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:29:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | const X: u32 = 7; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:53:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | const X: u32 = 8; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/name-value.rs:58:5 - | -LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ -... -LL | type T = (); - | ------------ not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error: aborting due to 19 previous errors +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0788`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/subword.stderr b/tests/ui/coverage-attr/subword.stderr index a5d1a492181be..32a09a10c8492 100644 --- a/tests/ui/coverage-attr/subword.stderr +++ b/tests/ui/coverage-attr/subword.stderr @@ -1,10 +1,12 @@ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:8:1 | LL | #[coverage(yes(milord))] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^-----------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(yes(milord))] LL + #[coverage(off)] @@ -13,13 +15,15 @@ LL - #[coverage(yes(milord))] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:11:1 | LL | #[coverage(no(milord))] - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^----------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(no(milord))] LL + #[coverage(off)] @@ -28,13 +32,15 @@ LL - #[coverage(no(milord))] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:14:1 | LL | #[coverage(yes = "milord")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^--------------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(yes = "milord")] LL + #[coverage(off)] @@ -43,13 +49,15 @@ LL - #[coverage(yes = "milord")] LL + #[coverage(on)] | -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/subword.rs:17:1 | LL | #[coverage(no = "milord")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^-------------^^ + | | + | valid arguments are `on` or `off` | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[coverage(no = "milord")] LL + #[coverage(off)] @@ -60,3 +68,4 @@ LL + #[coverage(on)] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs index d0f743938f3af..81bd558b8b002 100644 --- a/tests/ui/coverage-attr/word-only.rs +++ b/tests/ui/coverage-attr/word-only.rs @@ -20,7 +20,6 @@ mod my_mod_inner { #[coverage] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] struct MyStruct; #[coverage] @@ -28,22 +27,18 @@ struct MyStruct; impl MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 7; } #[coverage] //~^ ERROR malformed `coverage` attribute input -//~| ERROR [E0788] trait MyTrait { #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32; #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T; } @@ -52,12 +47,10 @@ trait MyTrait { impl MyTrait for MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] const X: u32 = 8; #[coverage] //~^ ERROR malformed `coverage` attribute input - //~| ERROR [E0788] type T = (); } diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr index 2773db9c85786..dd161360a5c4b 100644 --- a/tests/ui/coverage-attr/word-only.stderr +++ b/tests/ui/coverage-attr/word-only.stderr @@ -1,240 +1,161 @@ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:12:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:17:5 | LL | #![coverage] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute + | +LL - #![coverage] +LL + #[coverage(off)] + | +LL - #![coverage] +LL + #[coverage(on)] | -LL | #![coverage(off)] - | +++++ -LL | #![coverage(on)] - | ++++ -error: malformed `coverage` attribute input +error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:21:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:26:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:25:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:29:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:28:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:35:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:33:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:39:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:36:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:44:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:40:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:50:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:45:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:53:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:48:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:58:5 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:52:5 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error: malformed `coverage` attribute input - --> $DIR/word-only.rs:64:1 +error[E0539]: malformed `coverage` attribute input + --> $DIR/word-only.rs:57:1 | LL | #[coverage] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | -help: the following are the possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[coverage(off)] | +++++ LL | #[coverage(on)] | ++++ -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:21:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | struct MyStruct; - | ---------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:35:1 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | / trait MyTrait { -LL | | #[coverage] -... | -LL | | type T; -LL | | } - | |_- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:39:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | const X: u32; - | ------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:44:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | type T; - | ------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:29:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | const X: u32 = 7; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:53:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | const X: u32 = 8; - | ----------------- not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error[E0788]: coverage attribute not allowed here - --> $DIR/word-only.rs:58:5 - | -LL | #[coverage] - | ^^^^^^^^^^^ -... -LL | type T = (); - | ------------ not a function, impl block, or module - | - = help: coverage attribute can be applied to a function (with body), impl block, or module - -error: aborting due to 19 previous errors +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0788`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs b/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs new file mode 100644 index 0000000000000..cdcb5995a0f08 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs @@ -0,0 +1,22 @@ +//@ only-x86_64 + +use std::arch::{asm, global_asm, naked_asm}; + +global_asm!("/* {} */", const &0); +//~^ ERROR using pointers in asm `const` operand is experimental + +#[unsafe(naked)] +extern "C" fn naked() { + unsafe { + naked_asm!("ret /* {} */", const &0); + //~^ ERROR using pointers in asm `const` operand is experimental + } +} + +fn main() { + naked(); + unsafe { + asm!("/* {} */", const &0); + //~^ ERROR using pointers in asm `const` operand is experimental + } +} diff --git a/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr b/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr new file mode 100644 index 0000000000000..a804d8fe44be5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr @@ -0,0 +1,33 @@ +error[E0658]: using pointers in asm `const` operand is experimental + --> $DIR/feature-gate-asm_const_ptr.rs:5:25 + | +LL | global_asm!("/* {} */", const &0); + | ^^^^^^^^ + | + = note: see issue #128464 for more information + = help: add `#![feature(asm_const_ptr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: using pointers in asm `const` operand is experimental + --> $DIR/feature-gate-asm_const_ptr.rs:11:36 + | +LL | naked_asm!("ret /* {} */", const &0); + | ^^^^^^^^ + | + = note: see issue #128464 for more information + = help: add `#![feature(asm_const_ptr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: using pointers in asm `const` operand is experimental + --> $DIR/feature-gate-asm_const_ptr.rs:19:26 + | +LL | asm!("/* {} */", const &0); + | ^^^^^^^^ + | + = note: see issue #128464 for more information + = help: add `#![feature(asm_const_ptr)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs index 316c612940c9f..439793ea8f72e 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs @@ -1,6 +1,6 @@ //@ edition:2018 #![crate_type = "lib"] -#![feature(type_ascription)] +#![feature(type_ascription, const_index, const_trait_impl)] use std::future::Future; use std::pin::Pin; @@ -129,7 +129,6 @@ pub fn inside_block() { static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); //~^ ERROR: cast cannot be followed by indexing -//~| ERROR: cannot call non-const operator in statics static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); //~^ ERROR: expected one of diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr index 64cf8baf9a5d4..ce7129da9371f 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -219,13 +219,13 @@ LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]); | + + error: expected one of `)`, `,`, `.`, `?`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:134:36 + --> $DIR/issue-35813-postfix-after-cast.rs:133:36 | LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); | ^ expected one of `)`, `,`, `.`, `?`, or an operator error: cast cannot be followed by `?` - --> $DIR/issue-35813-postfix-after-cast.rs:139:5 + --> $DIR/issue-35813-postfix-after-cast.rs:138:5 | LL | Err(0u64) as Result?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,25 +236,25 @@ LL | (Err(0u64) as Result)?; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:141:14 + --> $DIR/issue-35813-postfix-after-cast.rs:140:14 | LL | Err(0u64): Result?; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: expected identifier, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:153:13 + --> $DIR/issue-35813-postfix-after-cast.rs:152:13 | LL | drop_ptr: F(); | ^ expected identifier error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:160:13 + --> $DIR/issue-35813-postfix-after-cast.rs:159:13 | LL | drop_ptr: fn(u8); | ^ expected one of 8 possible tokens error: cast cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:166:5 + --> $DIR/issue-35813-postfix-after-cast.rs:165:5 | LL | drop as fn(u8)(0); | ^^^^^^^^^^^^^^ @@ -265,13 +265,13 @@ LL | (drop as fn(u8))(0); | + + error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:168:13 + --> $DIR/issue-35813-postfix-after-cast.rs:167:13 | LL | drop_ptr: fn(u8)(0); | ^ expected one of 8 possible tokens error: cast cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:173:5 + --> $DIR/issue-35813-postfix-after-cast.rs:172:5 | LL | Box::pin(noop()) as Pin>>.await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -282,13 +282,13 @@ LL | (Box::pin(noop()) as Pin>>).await; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:176:21 + --> $DIR/issue-35813-postfix-after-cast.rs:175:21 | LL | Box::pin(noop()): Pin>.await; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: cast cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:188:5 + --> $DIR/issue-35813-postfix-after-cast.rs:187:5 | LL | Foo::default() as Foo.bar; | ^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ LL | (Foo::default() as Foo).bar; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:190:19 + --> $DIR/issue-35813-postfix-after-cast.rs:189:19 | LL | Foo::default(): Foo.bar; | ^ expected one of `.`, `;`, `?`, `}`, or an operator @@ -322,21 +322,11 @@ LL | if true { 33 } else { 44 }: i32.max(0) | ^ expected one of `,`, `.`, `?`, or an operator error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:151:13 + --> $DIR/issue-35813-postfix-after-cast.rs:150:13 | LL | drop as F(); | ^^^ only `Fn` traits may use parentheses -error[E0015]: cannot call non-const operator in statics - --> $DIR/issue-35813-postfix-after-cast.rs:130:42 - | -LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); - | ^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` - -error: aborting due to 40 previous errors +error: aborting due to 39 previous errors -Some errors have detailed explanations: E0015, E0214. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0214`. diff --git a/tests/ui/traits/const-traits/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs index dc960422a4a41..da28d9a47c31e 100644 --- a/tests/ui/traits/const-traits/const-impl-trait.rs +++ b/tests/ui/traits/const-traits/const-impl-trait.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Znext-solver //@ known-bug: #110395 -// Broken until we have `const PartialEq` impl in stdlib +// Broken until `(): const PartialEq` #![allow(incomplete_features)] #![feature(const_trait_impl, const_cmp, const_destruct)] diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr index 5bde358001cbc..f5d90544411b2 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr @@ -4,6 +4,7 @@ error[E0658]: use of unstable library feature `derive_const` LL | #[derive_const(Debug)] | ^^^^^^^^^^^^ | + = note: see issue #118304 for more information = help: add `#![feature(derive_const)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr deleted file mode 100644 index 89e59e5db6ed3..0000000000000 --- a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0015]: cannot match on `str` in constant functions - --> $DIR/match-non-const-eq.rs:7:9 - | -LL | "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts - | ^^^ - | - = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/match-non-const-eq.rs b/tests/ui/traits/const-traits/match-non-const-eq.rs index 73f8af86bd050..03adb8dc5a4e5 100644 --- a/tests/ui/traits/const-traits/match-non-const-eq.rs +++ b/tests/ui/traits/const-traits/match-non-const-eq.rs @@ -1,11 +1,12 @@ -//@ known-bug: #110395 //@ revisions: stock gated -#![cfg_attr(gated, feature(const_trait_impl))] +#![cfg_attr(gated, feature(const_trait_impl, const_cmp))] +//@[gated] check-pass const fn foo(input: &'static str) { match input { - "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts - //FIXME ~^ ERROR cannot match on `str` in constant functions + "a" => (), + //[stock]~^ ERROR cannot match on `str` in constant functions + //[stock]~| ERROR `PartialEq` is not yet stable as a const trait _ => (), } } diff --git a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr index 89e59e5db6ed3..afdd07311ea04 100644 --- a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr +++ b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr @@ -1,12 +1,26 @@ -error[E0015]: cannot match on `str` in constant functions +error[E0658]: cannot match on `str` in constant functions --> $DIR/match-non-const-eq.rs:7:9 | -LL | "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in const contexts +LL | "a" => (), | ^^^ | = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error: `PartialEq` is not yet stable as a const trait + --> $DIR/match-non-const-eq.rs:7:9 + | +LL | "a" => (), + | ^^^ + | +help: add `#![feature(const_cmp)]` to the crate attributes to enable + | +LL + #![feature(const_cmp)] + | + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0658`.