diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 923fd65dccaf9..af53c7ec21572 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -379,16 +379,16 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } - /// Create an `ExprKind::Ret` that is preceded by a call to check contract ensures clause. + /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check + /// a contract ensures clause, if it exists. fn checked_return(&mut self, opt_expr: Option<&'hir hir::Expr<'hir>>) -> hir::ExprKind<'hir> { - let checked_ret = if let Some(Some((span, fresh_ident))) = - self.contract.as_ref().map(|c| c.ensures.as_ref().map(|e| (e.expr.span, e.fresh_ident))) - { - let expr = opt_expr.unwrap_or_else(|| self.expr_unit(span)); - Some(self.inject_ensures_check(expr, span, fresh_ident.0, fresh_ident.2)) - } else { - opt_expr - }; + let checked_ret = + if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures { + let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span)); + Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id)) + } else { + opt_expr + }; hir::ExprKind::Ret(checked_ret) } @@ -1090,7 +1090,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { None }; - let body_id = this.lower_fn_body(decl, |this| { + // FIXME(contracts): Support contracts on closures? + let body_id = this.lower_fn_body(decl, None, |this| { this.coroutine_kind = coroutine_kind; let e = this.lower_expr_mut(body); coroutine_kind = this.coroutine_kind; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 75b08e16cdbd9..85642c8ccb56e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -211,36 +211,6 @@ impl<'hir> LoweringContext<'_, 'hir> { .. }) => { self.with_new_scopes(*fn_sig_span, |this| { - assert!(this.contract.is_none()); - if let Some(contract) = contract { - let requires = contract.requires.clone(); - let ensures = contract.ensures.clone(); - let ensures = ensures.map(|ens| { - // FIXME: this needs to be a fresh (or illegal) identifier to prevent - // accidental capture of a parameter or global variable. - let checker_ident: Ident = - Ident::from_str_and_span("__ensures_checker", ens.span); - let (checker_pat, checker_hir_id) = this.pat_ident_binding_mode_mut( - ens.span, - checker_ident, - hir::BindingMode::NONE, - ); - - crate::FnContractLoweringEnsures { - expr: ens, - fresh_ident: (checker_ident, checker_pat, checker_hir_id), - } - }); - - // Note: `with_new_scopes` will reinstall the outer - // item's contract (if any) after its callback finishes. - this.contract.replace(crate::FnContractLoweringInfo { - span, - requires, - ensures, - }); - } - // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body // only cares about the input argument patterns in the function @@ -254,6 +224,7 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind, body.as_deref(), attrs, + contract.as_deref(), ); let itctx = ImplTraitContext::Universal; @@ -803,6 +774,8 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { + // FIXME(contracts): Deny contract here since it won't apply to + // any impl method or callees. let names = self.lower_fn_params_to_names(&sig.decl); let (generics, sig) = self.lower_method_sig( generics, @@ -814,7 +787,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } - AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { + AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), contract, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -823,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_kind, Some(body), attrs, + contract.as_deref(), ); let (generics, sig) = self.lower_method_sig( generics, @@ -931,7 +905,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Const(ty, body) }, ), - AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { + AssocItemKind::Fn(box Fn { sig, generics, body, contract, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -940,6 +914,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_kind, body.as_deref(), attrs, + contract.as_deref(), ); let (generics, sig) = self.lower_method_sig( generics, @@ -1088,72 +1063,89 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_fn_body( &mut self, decl: &FnDecl, + contract: Option<&FnContract>, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::BodyId { self.lower_body(|this| { let params = this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))); - let result = body(this); - - let opt_contract = this.contract.take(); + // Optionally lower the fn contract, which turns: + // // { body } - // ==> - // { contract_requires(PRECOND); { body } } - let Some(contract) = opt_contract else { return (params, result) }; - let result_ref = this.arena.alloc(result); - let lit_unit = |this: &mut LoweringContext<'_, 'hir>| { - this.expr(contract.span, hir::ExprKind::Tup(&[])) - }; - - let precond: hir::Stmt<'hir> = if let Some(req) = contract.requires { - let lowered_req = this.lower_expr_mut(&req); - let precond = this.expr_call_lang_item_fn_mut( - req.span, - hir::LangItem::ContractCheckRequires, - &*arena_vec![this; lowered_req], - ); - this.stmt_expr(req.span, precond) - } else { - let u = lit_unit(this); - this.stmt_expr(contract.span, u) - }; - - let (postcond_checker, result) = if let Some(ens) = contract.ensures { - let crate::FnContractLoweringEnsures { expr: ens, fresh_ident } = ens; - let lowered_ens: hir::Expr<'hir> = this.lower_expr_mut(&ens); - let postcond_checker = this.expr_call_lang_item_fn( - ens.span, - hir::LangItem::ContractBuildCheckEnsures, - &*arena_vec![this; lowered_ens], - ); - let checker_binding_pat = fresh_ident.1; - ( - this.stmt_let_pat( + // + // into: + // + // { contract_requires(PRECOND); let __postcond = |ret_val| POSTCOND; postcond({ body }) } + if let Some(contract) = contract { + let precond = if let Some(req) = &contract.requires { + // Lower the precondition check intrinsic. + let lowered_req = this.lower_expr_mut(&req); + let precond = this.expr_call_lang_item_fn_mut( + req.span, + hir::LangItem::ContractCheckRequires, + &*arena_vec![this; lowered_req], + ); + Some(this.stmt_expr(req.span, precond)) + } else { + None + }; + let (postcond, body) = if let Some(ens) = &contract.ensures { + let ens_span = this.lower_span(ens.span); + // Set up the postcondition `let` statement. + let check_ident: Ident = + Ident::from_str_and_span("__ensures_checker", ens_span); + let (checker_pat, check_hir_id) = this.pat_ident_binding_mode_mut( + ens_span, + check_ident, + hir::BindingMode::NONE, + ); + let lowered_ens = this.lower_expr_mut(&ens); + let postcond_checker = this.expr_call_lang_item_fn( + ens_span, + hir::LangItem::ContractBuildCheckEnsures, + &*arena_vec![this; lowered_ens], + ); + let postcond = this.stmt_let_pat( None, - ens.span, + ens_span, Some(postcond_checker), - this.arena.alloc(checker_binding_pat), + this.arena.alloc(checker_pat), hir::LocalSource::Contract, - ), - this.inject_ensures_check(result_ref, ens.span, fresh_ident.0, fresh_ident.2), - ) - } else { - let u = lit_unit(this); - (this.stmt_expr(contract.span, u), &*result_ref) - }; + ); - let block = this.block_all( - contract.span, - arena_vec![this; precond, postcond_checker], - Some(result), - ); - (params, this.expr_block(block)) + // Install contract_ensures so we will intercept `return` statements, + // then lower the body. + this.contract_ensures = Some((ens_span, check_ident, check_hir_id)); + let body = this.arena.alloc(body(this)); + + // Finally, inject an ensures check on the implicit return of the body. + let body = this.inject_ensures_check(body, ens_span, check_ident, check_hir_id); + (Some(postcond), body) + } else { + let body = &*this.arena.alloc(body(this)); + (None, body) + }; + // Flatten the body into precond, then postcond, then wrapped body. + let wrapped_body = this.block_all( + body.span, + this.arena.alloc_from_iter([precond, postcond].into_iter().flatten()), + Some(body), + ); + (params, this.expr_block(wrapped_body)) + } else { + (params, body(this)) + } }) } - fn lower_fn_body_block(&mut self, decl: &FnDecl, body: &Block) -> hir::BodyId { - self.lower_fn_body(decl, |this| this.lower_block_expr(body)) + fn lower_fn_body_block( + &mut self, + decl: &FnDecl, + body: &Block, + contract: Option<&FnContract>, + ) -> hir::BodyId { + self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) } pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { @@ -1179,12 +1171,13 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind: Option, body: Option<&Block>, attrs: &'hir [hir::Attribute], + contract: Option<&FnContract>, ) -> hir::BodyId { let Some(body) = body else { // Functions without a body are an error, except if this is an intrinsic. For those we // create a fake body so that the entire rest of the compiler doesn't have to deal with // this as a special case. - return self.lower_fn_body(decl, |this| { + return self.lower_fn_body(decl, contract, |this| { if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) { let span = this.lower_span(span); let empty_block = hir::Block { @@ -1209,8 +1202,9 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let Some(coroutine_kind) = coroutine_kind else { // Typical case: not a coroutine. - return self.lower_fn_body_block(decl, body); + return self.lower_fn_body_block(decl, body, contract); }; + // FIXME(contracts): Support contracts on async fn. self.lower_body(|this| { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3fecb9e9c7ea9..facc9414b20d5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -88,19 +88,6 @@ pub mod stability; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -#[derive(Debug, Clone)] -struct FnContractLoweringInfo<'hir> { - pub span: Span, - pub requires: Option>, - pub ensures: Option>, -} - -#[derive(Debug, Clone)] -struct FnContractLoweringEnsures<'hir> { - expr: ast::ptr::P, - fresh_ident: (Ident, hir::Pat<'hir>, HirId), -} - struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering, @@ -115,7 +102,7 @@ struct LoweringContext<'a, 'hir> { /// Collect items that were created by lowering the current owner. children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>, - contract: Option>, + contract_ensures: Option<(Span, Ident, HirId)>, coroutine_kind: Option, @@ -165,7 +152,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bodies: Vec::new(), attrs: SortedMap::default(), children: Vec::default(), - contract: None, + contract_ensures: None, current_hir_id_owner: hir::CRATE_OWNER_ID, item_local_id_counter: hir::ItemLocalId::ZERO, ident_and_label_to_local_id: Default::default(), @@ -852,7 +839,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; - let old_contract = self.contract.take(); + let old_contract = self.contract_ensures.take(); let catch_scope = self.catch_scope.take(); let loop_scope = self.loop_scope.take(); @@ -860,7 +847,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.catch_scope = catch_scope; self.loop_scope = loop_scope; - self.contract = old_contract; + self.contract_ensures = old_contract; self.is_in_loop_condition = was_in_loop_condition; diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs index 85a30f7bdc9b4..6a24af361fe78 100644 --- a/compiler/rustc_builtin_macros/src/contracts.rs +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -1,11 +1,9 @@ -#![allow(unused_imports, unused_variables)] - use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_errors::ErrorGuaranteed; use rustc_expand::base::{AttrProcMacro, ExtCtxt}; use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::symbol::{Ident, Symbol, kw}; pub(crate) struct ExpandRequires; @@ -121,23 +119,19 @@ fn expand_contract_clause( } } - // Record the span as a contract attribute expansion. - // This is used later to stop users from using the extended syntax directly - // which is gated via `contracts_internals`. - ecx.psess().contract_attribute_spans.push(attr_span); - Ok(new_tts) } fn expand_requires_tts( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_contract_clause(_ecx, attr_span, annotated, |new_tts| { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractRequires, attr_span)), + token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Token( @@ -155,14 +149,15 @@ fn expand_requires_tts( } fn expand_ensures_tts( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_contract_clause(_ecx, attr_span, annotated, |new_tts| { + let feature_span = ecx.with_def_site_ctxt(attr_span); + expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, attr_span)), + token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Delimited( diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 685b2f37c9c3d..13846c8ab4b96 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -664,7 +664,7 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { } impl llvm::CallConv { - pub fn from_conv(conv: Conv, arch: &str) -> Self { + pub(crate) fn from_conv(conv: Conv, arch: &str) -> Self { match conv { Conv::C | Conv::Rust diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 8bad437eeb716..7262fce491191 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -642,7 +642,7 @@ unsafe impl Send for ModuleBuffer {} unsafe impl Sync for ModuleBuffer {} impl ModuleBuffer { - pub fn new(m: &llvm::Module) -> ModuleBuffer { + pub(crate) fn new(m: &llvm::Module) -> ModuleBuffer { ModuleBuffer(unsafe { llvm::LLVMRustModuleBufferCreate(m) }) } } @@ -684,7 +684,7 @@ unsafe impl Send for ThinBuffer {} unsafe impl Sync for ThinBuffer {} impl ThinBuffer { - pub fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer { + pub(crate) fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer { unsafe { let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary); ThinBuffer(buffer) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 4cbd49aa44d48..f075f332462fc 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -17,7 +17,7 @@ pub struct OwnedTargetMachine { } impl OwnedTargetMachine { - pub fn new( + pub(crate) fn new( triple: &CStr, cpu: &CStr, features: &CStr, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index f0d04b2b64476..bcb1cc72b5603 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -30,7 +30,7 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; -pub use llvm_util::target_features_cfg; +pub(crate) use llvm_util::target_features_cfg; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53611c746a722..b4b5d6a5b1943 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -271,6 +271,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("fullfp16")), // Filter out features that are not supported by the current LLVM version ("aarch64", "fpmr") if get_version().0 != 18 => None, + ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single // feature called `fast-unaligned-access`. In LLVM 19, it was split back out. ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => { @@ -303,7 +304,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Vec { +pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec { let mut features: FxHashSet = Default::default(); // Add base features for the target. diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 34cede54aaf15..d61ce41756270 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -237,11 +237,11 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl Type { /// Creates an integer type with the given number of bits, e.g., i24 - pub fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type { + pub(crate) fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type { unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) } } - pub fn ptr_llcx(llcx: &llvm::Context) -> &Type { + pub(crate) fn ptr_llcx(llcx: &llvm::Context) -> &Type { unsafe { llvm::LLVMPointerTypeInContext(llcx, AddressSpace::DATA.0) } } } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index eb98e3b538051..ba579e25f036a 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,12 +1,8 @@ -use std::ops::ControlFlow; - use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, -}; +use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt}; use tracing::debug; use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval}; @@ -20,44 +16,10 @@ where T: TypeVisitable>, { debug!("ensure_monomorphic_enough: ty={:?}", ty); - if !ty.has_param() { - return interp_ok(()); - } - - struct FoundParam; - struct UsedParamsNeedInstantiationVisitor {} - - impl<'tcx> TypeVisitor> for UsedParamsNeedInstantiationVisitor { - type Result = ControlFlow; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - if !ty.has_param() { - return ControlFlow::Continue(()); - } - - match *ty.kind() { - ty::Param(_) => ControlFlow::Break(FoundParam), - ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::FnDef(..) => { - ControlFlow::Continue(()) - } - _ => ty.super_visit_with(self), - } - } - - fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { - match c.kind() { - ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), - _ => c.super_visit_with(self), - } - } - } - - let mut vis = UsedParamsNeedInstantiationVisitor {}; - if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { + if ty.has_param() { throw_inval!(TooGeneric); - } else { - interp_ok(()) } + interp_ok(()) } impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 86816819be275..11f0e579de5a1 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -302,26 +302,16 @@ impl<'a> Parser<'a> { pub(super) fn parse_contract( &mut self, ) -> PResult<'a, Option>> { - let gate = |span| { - if self.psess.contract_attribute_spans.contains(span) { - // span was generated via a builtin contracts attribute, so gate as end-user visible - self.psess.gated_spans.gate(sym::contracts, span); - } else { - // span was not generated via a builtin contracts attribute, so gate as internal machinery - self.psess.gated_spans.gate(sym::contracts_internals, span); - } - }; - let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { + self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let precond = self.parse_expr()?; - gate(precond.span); Some(precond) } else { None }; let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) { + self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let postcond = self.parse_expr()?; - gate(postcond.span); Some(postcond) } else { None diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index d4db05ce139fa..e0405a71f65af 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -208,10 +208,6 @@ pub struct ParseSess { pub config: Cfg, pub check_config: CheckCfg, pub edition: Edition, - /// Places where contract attributes were expanded into unstable AST forms. - /// This is used to allowlist those spans (so that we only check them against the feature - /// gate for the externally visible interface, and not internal implmentation machinery). - pub contract_attribute_spans: AppendOnlyVec, /// Places where raw identifiers were used. This is used to avoid complaining about idents /// clashing with keywords in new editions. pub raw_identifier_spans: AppendOnlyVec, @@ -260,7 +256,6 @@ impl ParseSess { config: Cfg::default(), check_config: CheckCfg::default(), edition: ExpnId::root().expn_data().edition, - contract_attribute_spans: Default::default(), raw_identifier_spans: Default::default(), bad_unicode_identifiers: Lock::new(Default::default()), source_map, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index ea7c15a359538..1ba8defedae13 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -145,6 +145,7 @@ static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("dotprod", Unstable(sym::arm_target_feature), &["neon"]), ("dsp", Unstable(sym::arm_target_feature), &[]), ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]), + ("fp16", Unstable(sym::arm_target_feature), &["neon"]), ("fpregs", Unstable(sym::arm_target_feature), &[]), ("i8mm", Unstable(sym::arm_target_feature), &["neon"]), ("mclass", Unstable(sym::arm_target_feature), &[]), diff --git a/config.example.toml b/config.example.toml index 7f6bbf2799288..1a8f42428ab87 100644 --- a/config.example.toml +++ b/config.example.toml @@ -323,7 +323,7 @@ #full-bootstrap = false # Set the bootstrap/download cache path. It is useful when building rust -# repeatedly in a CI invironment. +# repeatedly in a CI environment. #bootstrap-cache-path = /path/to/shared/cache # Enable a build of the extended Rust tool set which is not only the compiler diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index dcab6136ae8a1..9805cee1c331e 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -94,7 +94,7 @@ impl fmt::Display for AllocError { /// - the memory block is deallocated, or /// - the allocator is dropped. /// -/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it +/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it. /// A copied or cloned allocator must behave like the original allocator. /// /// A memory block which is [*currently allocated*] may be passed to diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index a115acf42b126..21bad6705ab80 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -612,8 +612,6 @@ macro_rules! nonzero_integer { /// Basic usage: /// /// ``` - /// #![feature(non_zero_count_ones)] - /// /// # use std::num::NonZero; /// # /// # fn main() { test().unwrap(); } @@ -627,7 +625,8 @@ macro_rules! nonzero_integer { /// # } /// ``` /// - #[unstable(feature = "non_zero_count_ones", issue = "120287")] + #[stable(feature = "non_zero_count_ones", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_zero_count_ones", since = "CURRENT_RUSTC_VERSION")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] #[must_use = "this returns the result of the operation, \ diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0871a9e22d386..83b009c86dc08 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -664,7 +664,7 @@ impl File { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; + /// let f = File::create("foo.txt")?; /// f.lock()?; /// Ok(()) /// } @@ -767,7 +767,7 @@ impl File { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; + /// let f = File::create("foo.txt")?; /// f.try_lock()?; /// Ok(()) /// } diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index 6d23c72ef2209..e305b8610c9f8 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -17,111 +17,50 @@ pub fn errno() -> RawOsError { pub fn error_string(errno: RawOsError) -> String { // Keep the List in Alphabetical Order // The Messages are taken from UEFI Specification Appendix D - Status Codes - match r_efi::efi::Status::from_usize(errno) { - Status::ABORTED => "The operation was aborted.".to_owned(), - Status::ACCESS_DENIED => "Access was denied.".to_owned(), - Status::ALREADY_STARTED => "The protocol has already been started.".to_owned(), - Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.".to_owned(), - Status::BUFFER_TOO_SMALL => { - "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.".to_owned() - } - Status::COMPROMISED_DATA => { - "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.".to_owned() - } - Status::CONNECTION_FIN => { - "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.".to_owned() - } - Status::CONNECTION_REFUSED => { - "The receiving or transmission operation fails because this connection is refused.".to_owned() - } - Status::CONNECTION_RESET => { - "The connect fails because the connection is reset either by instance itself or the communication peer.".to_owned() - } - Status::CRC_ERROR => "A CRC error was detected.".to_owned(), - Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.".to_owned() - , - Status::END_OF_FILE => { - "The end of the file was reached.".to_owned() - } - Status::END_OF_MEDIA => { - "Beginning or end of media was reached".to_owned() - } - Status::HOST_UNREACHABLE => { - "The remote host is not reachable.".to_owned() - } - Status::HTTP_ERROR => { - "A HTTP error occurred during the network operation.".to_owned() - } - Status::ICMP_ERROR => { - "An ICMP error occurred during the network operation.".to_owned() - } - Status::INCOMPATIBLE_VERSION => { - "The function encountered an internal version that was incompatible with a version requested by the caller.".to_owned() - } - Status::INVALID_LANGUAGE => { - "The language specified was invalid.".to_owned() - } - Status::INVALID_PARAMETER => { - "A parameter was incorrect.".to_owned() - } - Status::IP_ADDRESS_CONFLICT => { - "There is an address conflict address allocation".to_owned() - } - Status::LOAD_ERROR => { - "The image failed to load.".to_owned() - } - Status::MEDIA_CHANGED => { - "The medium in the device has changed since the last access.".to_owned() - } - Status::NETWORK_UNREACHABLE => { - "The network containing the remote host is not reachable.".to_owned() - } - Status::NO_MAPPING => { - "A mapping to a device does not exist.".to_owned() - } - Status::NO_MEDIA => { - "The device does not contain any medium to perform the operation.".to_owned() - } - Status::NO_RESPONSE => { - "The server was not found or did not respond to the request.".to_owned() - } - Status::NOT_FOUND => "The item was not found.".to_owned(), - Status::NOT_READY => { - "There is no data pending upon return.".to_owned() - } - Status::NOT_STARTED => { - "The protocol has not been started.".to_owned() - } - Status::OUT_OF_RESOURCES => { - "A resource has run out.".to_owned() - } - Status::PROTOCOL_ERROR => { - "A protocol error occurred during the network operation.".to_owned() - } - Status::PROTOCOL_UNREACHABLE => { - "An ICMP protocol unreachable error is received.".to_owned() - } - Status::SECURITY_VIOLATION => { - "The function was not performed due to a security violation.".to_owned() - } - Status::TFTP_ERROR => { - "A TFTP error occurred during the network operation.".to_owned() - } - Status::TIMEOUT => "The timeout time expired.".to_owned(), - Status::UNSUPPORTED => { - "The operation is not supported.".to_owned() - } - Status::VOLUME_FULL => { - "There is no more space on the file system.".to_owned() - } - Status::VOLUME_CORRUPTED => { - "An inconstancy was detected on the file system causing the operating to fail.".to_owned() - } - Status::WRITE_PROTECTED => { - "The device cannot be written to.".to_owned() - } - _ => format!("Status: {}", errno), - } + #[rustfmt::skip] + let msg = match r_efi::efi::Status::from_usize(errno) { + Status::ABORTED => "The operation was aborted.", + Status::ACCESS_DENIED => "Access was denied.", + Status::ALREADY_STARTED => "The protocol has already been started.", + Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.", + Status::BUFFER_TOO_SMALL => "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.", + Status::COMPROMISED_DATA => "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.", + Status::CONNECTION_FIN => "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.", + Status::CONNECTION_REFUSED => "The receiving or transmission operation fails because this connection is refused.", + Status::CONNECTION_RESET => "The connect fails because the connection is reset either by instance itself or the communication peer.", + Status::CRC_ERROR => "A CRC error was detected.", + Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.", + Status::END_OF_FILE => "The end of the file was reached.", + Status::END_OF_MEDIA => "Beginning or end of media was reached", + Status::HOST_UNREACHABLE => "The remote host is not reachable.", + Status::HTTP_ERROR => "A HTTP error occurred during the network operation.", + Status::ICMP_ERROR => "An ICMP error occurred during the network operation.", + Status::INCOMPATIBLE_VERSION => "The function encountered an internal version that was incompatible with a version requested by the caller.", + Status::INVALID_LANGUAGE => "The language specified was invalid.", + Status::INVALID_PARAMETER => "A parameter was incorrect.", + Status::IP_ADDRESS_CONFLICT => "There is an address conflict address allocation", + Status::LOAD_ERROR => "The image failed to load.", + Status::MEDIA_CHANGED => "The medium in the device has changed since the last access.", + Status::NETWORK_UNREACHABLE => "The network containing the remote host is not reachable.", + Status::NO_MAPPING => "A mapping to a device does not exist.", + Status::NO_MEDIA => "The device does not contain any medium to perform the operation.", + Status::NO_RESPONSE => "The server was not found or did not respond to the request.", + Status::NOT_FOUND => "The item was not found.", + Status::NOT_READY => "There is no data pending upon return.", + Status::NOT_STARTED => "The protocol has not been started.", + Status::OUT_OF_RESOURCES => "A resource has run out.", + Status::PROTOCOL_ERROR => "A protocol error occurred during the network operation.", + Status::PROTOCOL_UNREACHABLE => "An ICMP protocol unreachable error is received.", + Status::SECURITY_VIOLATION => "The function was not performed due to a security violation.", + Status::TFTP_ERROR => "A TFTP error occurred during the network operation.", + Status::TIMEOUT => "The timeout time expired.", + Status::UNSUPPORTED => "The operation is not supported.", + Status::VOLUME_FULL => "There is no more space on the file system.", + Status::VOLUME_CORRUPTED => "An inconstancy was detected on the file system causing the operating to fail.", + Status::WRITE_PROTECTED => "The device cannot be written to.", + _ => return format!("Status: {errno}"), + }; + msg.to_owned() } pub fn getcwd() -> io::Result { @@ -314,7 +253,7 @@ mod uefi_env { let mut start = 0; - // UEFI Shell returns all keys seperated by NULL. + // UEFI Shell returns all keys separated by NULL. // End of string is denoted by two NULLs for i in 0.. { if unsafe { *val.add(i) } == 0 { diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index bb89d97a7984d..05555f537c962 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -169,7 +169,7 @@ target | std | notes [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI] [`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI] -[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? (Pentium 4, softfloat) | 32-bit UEFI +[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat) [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI) [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] @@ -313,7 +313,7 @@ target | std | host | notes [`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86 (original Pentium) [^x86_32-floats-x87] [`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI] `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI] -[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-x87] +[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS (PentiumPro) [^x86_32-floats-x87] diff --git a/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff b/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff new file mode 100644 index 0000000000000..2f83f54d2afdb --- /dev/null +++ b/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff @@ -0,0 +1,12 @@ +- // MIR for `cursed_is_i32` before GVN ++ // MIR for `cursed_is_i32` after GVN + + fn cursed_is_i32() -> bool { + let mut _0: bool; + + bb0: { + _0 = Eq(const cursed_is_i32::::{constant#0}, const cursed_is_i32::::{constant#1}); + return; + } + } + diff --git a/tests/mir-opt/gvn_type_id_polymorphic.rs b/tests/mir-opt/gvn_type_id_polymorphic.rs new file mode 100644 index 0000000000000..39bc5c24ecc68 --- /dev/null +++ b/tests/mir-opt/gvn_type_id_polymorphic.rs @@ -0,0 +1,22 @@ +//@ test-mir-pass: GVN +//@ compile-flags: -C opt-level=2 + +#![feature(core_intrinsics)] + +fn generic() {} + +const fn type_id_of_val(_: &T) -> u128 { + std::intrinsics::type_id::() +} + +// EMIT_MIR gvn_type_id_polymorphic.cursed_is_i32.GVN.diff +fn cursed_is_i32() -> bool { + // CHECK-LABEL: fn cursed_is_i32( + // CHECK: _0 = Eq(const cursed_is_i32::::{constant#0}, const cursed_is_i32::::{constant#1}); + // CHECK-NEXT: return; + (const { type_id_of_val(&generic::) } == const { type_id_of_val(&generic::) }) +} + +fn main() { + dbg!(cursed_is_i32::()); +} diff --git a/tests/ui/contracts/associated-item.rs b/tests/ui/contracts/associated-item.rs new file mode 100644 index 0000000000000..4a2d05abbc53c --- /dev/null +++ b/tests/ui/contracts/associated-item.rs @@ -0,0 +1,18 @@ +// Ensure we don't ICE when lowering contracts on an associated item. + +//@ compile-flags: --crate-type=lib +//@ check-pass + +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use + +extern crate core; + +use core::contracts::requires; + +struct Foo; + +impl Foo { + #[requires(align > 0 && (align & (align - 1)) == 0)] + pub fn foo(align: i32) {} +} diff --git a/tests/ui/contracts/associated-item.stderr b/tests/ui/contracts/associated-item.stderr new file mode 100644 index 0000000000000..20651026b87a2 --- /dev/null +++ b/tests/ui/contracts/associated-item.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/associated-item.rs:6:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr index c0e1522f54c61..7302694a7874a 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr @@ -1,18 +1,18 @@ error[E0658]: contract internal machinery is for internal use only - --> $DIR/internal-feature-gating.rs:16:45 + --> $DIR/internal-feature-gating.rs:16:28 | LL | fn identity_1() -> i32 contract_requires(|| true) { 10 } - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information = help: add `#![feature(contracts_internals)]` 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]: contract internal machinery is for internal use only - --> $DIR/internal-feature-gating.rs:18:44 + --> $DIR/internal-feature-gating.rs:18:28 | LL | fn identity_2() -> i32 contract_ensures(|_| true) { 10 } - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information = help: add `#![feature(contracts_internals)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-contracts.rs b/tests/ui/feature-gates/feature-gate-contracts.rs index 5544f1d82ee4c..1759d23077b53 100644 --- a/tests/ui/feature-gates/feature-gate-contracts.rs +++ b/tests/ui/feature-gates/feature-gate-contracts.rs @@ -3,9 +3,7 @@ #[core::contracts::requires(x > 0)] pub fn requires_needs_it(x: i32) { } //~^^ ERROR use of unstable library feature `contracts` -//~^^^ ERROR contracts are incomplete #[core::contracts::ensures(|ret| *ret > 0)] pub fn ensures_needs_it() -> i32 { 10 } //~^^ ERROR use of unstable library feature `contracts` -//~^^^ ERROR contracts are incomplete diff --git a/tests/ui/feature-gates/feature-gate-contracts.stderr b/tests/ui/feature-gates/feature-gate-contracts.stderr index 4403e7df50b49..4b0f7150973f1 100644 --- a/tests/ui/feature-gates/feature-gate-contracts.stderr +++ b/tests/ui/feature-gates/feature-gate-contracts.stderr @@ -9,7 +9,7 @@ LL | #[core::contracts::requires(x > 0)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `contracts` - --> $DIR/feature-gate-contracts.rs:8:3 + --> $DIR/feature-gate-contracts.rs:7:3 | LL | #[core::contracts::ensures(|ret| *ret > 0)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,26 +18,6 @@ LL | #[core::contracts::ensures(|ret| *ret > 0)] = help: add `#![feature(contracts)]` 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]: contracts are incomplete - --> $DIR/feature-gate-contracts.rs:3:1 - | -LL | #[core::contracts::requires(x > 0)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #128044 for more information - = help: add `#![feature(contracts)]` 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]: contracts are incomplete - --> $DIR/feature-gate-contracts.rs:8:1 - | -LL | #[core::contracts::ensures(|ret| *ret > 0)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #128044 for more information - = help: add `#![feature(contracts)]` 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 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`.