diff options
Diffstat (limited to 'compiler')
48 files changed, 704 insertions, 399 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4a3ce0e0c30..f5e79c04d78 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1454,7 +1454,10 @@ pub enum ExprKind { Block(P<Block>, Option<Label>), /// An `async` block (`async move { ... }`), /// or a `gen` block (`gen move { ... }`) - Gen(CaptureBy, P<Block>, GenBlockKind), + /// + /// The span is the "decl", which is the header before the body `{ }` + /// including the `asyng`/`gen` keywords and possibly `move`. + Gen(CaptureBy, P<Block>, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(P<Expr>, Span), diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a81c335aa23..27e781a5a63 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1528,8 +1528,9 @@ pub fn noop_visit_expr<T: MutVisitor>( visit_opt(label, |label| vis.visit_label(label)); vis.visit_block(blk); } - ExprKind::Gen(_capture_by, body, _kind) => { + ExprKind::Gen(_capture_by, body, _kind, decl_span) => { vis.visit_block(body); + vis.visit_span(decl_span); } ExprKind::Await(expr, await_kw_span) => { vis.visit_expr(expr); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 0f3c30048ce..26cb04d4d47 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1122,7 +1122,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V visit_opt!(visitor, visit_label, opt_label); try_visit!(visitor.visit_block(block)); } - ExprKind::Gen(_capt, body, _kind) => try_visit!(visitor.visit_block(body)), + ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)), ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)), ExprKind::Assign(lhs, rhs, _span) => { try_visit!(visitor.visit_expr(lhs)); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 79cff0fbcd2..624bca525b9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -227,7 +227,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_arg_span, ), }, - ExprKind::Gen(capture_clause, block, genblock_kind) => { + ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { let desugaring_kind = match genblock_kind { GenBlockKind::Async => hir::CoroutineDesugaring::Async, GenBlockKind::Gen => hir::CoroutineDesugaring::Gen, @@ -237,6 +237,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *capture_clause, e.id, None, + *decl_span, e.span, desugaring_kind, hir::CoroutineSource::Block, @@ -616,6 +617,7 @@ impl<'hir> LoweringContext<'_, 'hir> { capture_clause: CaptureBy, closure_node_id: NodeId, return_ty: Option<hir::FnRetTy<'hir>>, + fn_decl_span: Span, span: Span, desugaring_kind: hir::CoroutineDesugaring, coroutine_source: hir::CoroutineSource, @@ -692,7 +694,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params: &[], fn_decl, body, - fn_decl_span: self.lower_span(span), + fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: None, kind: hir::ClosureKind::Coroutine(coroutine_kind), constness: hir::Constness::NotConst, @@ -1083,6 +1085,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( &inner_decl, |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), + fn_decl_span, body.span, coroutine_kind, hir::CoroutineSource::Closure, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4c7e8c24d32..74e04eff4f3 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -211,6 +211,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // declaration (decl), not the return types. let coroutine_kind = header.coroutine_kind; let body_id = this.lower_maybe_coroutine_body( + *fn_sig_span, span, hir_id, decl, @@ -799,6 +800,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { let body_id = self.lower_maybe_coroutine_body( + sig.span, i.span, hir_id, &sig.decl, @@ -915,6 +917,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { let body_id = self.lower_maybe_coroutine_body( + sig.span, i.span, hir_id, &sig.decl, @@ -1111,6 +1114,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `gen {}` block as appropriate. fn lower_maybe_coroutine_body( &mut self, + fn_decl_span: Span, span: Span, fn_id: hir::HirId, decl: &FnDecl, @@ -1124,6 +1128,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( decl, |this| this.lower_block_expr(body), + fn_decl_span, body.span, coroutine_kind, hir::CoroutineSource::Fn, @@ -1145,6 +1150,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, decl: &FnDecl, lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>, + fn_decl_span: Span, body_span: Span, coroutine_kind: CoroutineKind, coroutine_source: hir::CoroutineSource, @@ -1315,13 +1321,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let closure_id = coroutine_kind.closure_id(); - let span = if let FnRetTy::Default(span) = decl.output - && matches!(coroutine_source, rustc_hir::CoroutineSource::Closure) - { - body_span.with_lo(span.lo()) - } else { - body_span - }; let coroutine_expr = self.make_desugared_coroutine_expr( // The default capture mode here is by-ref. Later on during upvar analysis, // we will force the captured arguments to by-move, but for async closures, @@ -1330,7 +1329,8 @@ impl<'hir> LoweringContext<'_, 'hir> { CaptureBy::Ref, closure_id, None, - span, + fn_decl_span, + body_span, desugaring_kind, coroutine_source, mkbody, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ba4b6130b60..79ee5c0e8e2 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1,10 +1,20 @@ -// Validate AST before lowering it to HIR. -// -// This pass is supposed to catch things that fit into AST data structures, -// but not permitted by the language. It runs after expansion when AST is frozen, -// so it can check for erroneous constructions produced by syntax extensions. -// This pass is supposed to perform only simple checks not requiring name resolution -// or type checking or some other kind of complex analysis. +//! Validate AST before lowering it to HIR. +//! +//! This pass intends to check that the constructed AST is *syntactically valid* to allow the rest +//! of the compiler to assume that the AST is valid. These checks cannot be performed during parsing +//! because attribute macros are allowed to accept certain pieces of invalid syntax such as a +//! function without body outside of a trait definition: +//! +//! ```ignore (illustrative) +//! #[my_attribute] +//! mod foo { +//! fn missing_body(); +//! } +//! ``` +//! +//! These checks are run post-expansion, after AST is frozen, to be able to check for erroneous +//! constructions produced by proc macros. This pass is only intended for simple checks that do not +//! require name resolution or type checking, or other kinds of complex analysis. use itertools::{Either, Itertools}; use rustc_ast::ptr::P; diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index f2f6594e686..3d1f43a3766 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -540,7 +540,7 @@ impl<'a> State<'a> { self.ibox(0); self.print_block_with_attrs(blk, attrs); } - ast::ExprKind::Gen(capture_clause, blk, kind) => { + ast::ExprKind::Gen(capture_clause, blk, kind, _decl_span) => { self.word_nbsp(kind.modifier()); self.print_capture_clause(*capture_clause); // cbox/ibox in analogy to the `ExprKind::Block` arm above diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index a98cb6f0f76..c664891dad5 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -298,7 +298,7 @@ impl<'cx, 'a> Context<'cx, 'a> { // sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test. ExprKind::Assign(_, _, _) | ExprKind::AssignOp(_, _, _) - | ExprKind::Gen(_, _, _) + | ExprKind::Gen(_, _, _, _) | ExprKind::Await(_, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 48693895da1..cd82894af18 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -2,7 +2,7 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; @@ -53,6 +53,34 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll } } +#[inline] +fn patchable_function_entry_attrs<'ll>( + cx: &CodegenCx<'ll, '_>, + attr: Option<PatchableFunctionEntry>, +) -> SmallVec<[&'ll Attribute; 2]> { + let mut attrs = SmallVec::new(); + let patchable_spec = attr.unwrap_or_else(|| { + PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry) + }); + let entry = patchable_spec.entry(); + let prefix = patchable_spec.prefix(); + if entry > 0 { + attrs.push(llvm::CreateAttrStringValue( + cx.llcx, + "patchable-function-entry", + &format!("{}", entry), + )); + } + if prefix > 0 { + attrs.push(llvm::CreateAttrStringValue( + cx.llcx, + "patchable-function-prefix", + &format!("{}", prefix), + )); + } + attrs +} + /// Get LLVM sanitize attributes. #[inline] pub fn sanitize_attrs<'ll>( @@ -421,6 +449,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( llvm::set_alignment(llfn, align); } to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); + to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d224695d1f2..56a893738df 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,11 +1,13 @@ use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; -use rustc_errors::{codes::*, struct_span_code_err}; +use rustc_errors::{codes::*, struct_span_code_err, DiagMessage, SubdiagMessage}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem}; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::codegen_fn_attrs::{ + CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, +}; use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; @@ -447,6 +449,80 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { None }; } + sym::patchable_function_entry => { + codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| { + let mut prefix = None; + let mut entry = None; + for item in l { + let Some(meta_item) = item.meta_item() else { + tcx.dcx().span_err(item.span(), "expected name value pair"); + continue; + }; + + let Some(name_value_lit) = meta_item.name_value_literal() else { + tcx.dcx().span_err(item.span(), "expected name value pair"); + continue; + }; + + fn emit_error_with_label( + tcx: TyCtxt<'_>, + span: Span, + error: impl Into<DiagMessage>, + label: impl Into<SubdiagMessage>, + ) { + let mut err: rustc_errors::Diag<'_, _> = + tcx.dcx().struct_span_err(span, error); + err.span_label(span, label); + err.emit(); + } + + let attrib_to_write = match meta_item.name_or_empty() { + sym::prefix_nops => &mut prefix, + sym::entry_nops => &mut entry, + _ => { + emit_error_with_label( + tcx, + item.span(), + "unexpected parameter name", + format!("expected {} or {}", sym::prefix_nops, sym::entry_nops), + ); + continue; + } + }; + + let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { + emit_error_with_label( + tcx, + name_value_lit.span, + "invalid literal value", + "value must be an integer between `0` and `255`", + ); + continue; + }; + + let Ok(val) = val.get().try_into() else { + emit_error_with_label( + tcx, + name_value_lit.span, + "integer value out of range", + "value must be between `0` and `255`", + ); + continue; + }; + + *attrib_to_write = Some(val); + } + + if let (None, None) = (prefix, entry) { + tcx.dcx().span_err(attr.span, "must specify at least one parameter"); + } + + Some(PatchableFunctionEntry::from_prefix_and_entry( + prefix.unwrap_or(0), + entry.unwrap_or(0), + )) + }) + } _ => {} } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index a13630ce084..83b61ab1749 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,6 +1,6 @@ use std::assert_matches::assert_matches; -use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::mir::CastKind; @@ -187,10 +187,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bug!("FloatToFloat/FloatToInt cast: source type {} is not a float type", src.layout.ty) }; let val = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => self.cast_from_float(src.to_scalar().to_f16()?, cast_to.ty), FloatTy::F32 => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty), FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty), }; Ok(ImmTy::from_scalar(val, cast_to)) } @@ -296,18 +296,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Float(fty) if signed => { let v = v as i128; match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(Half::from_i128(v).value), FloatTy::F32 => Scalar::from_f32(Single::from_i128(v).value), FloatTy::F64 => Scalar::from_f64(Double::from_i128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => Scalar::from_f128(Quad::from_i128(v).value), } } // unsigned int -> float Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(Half::from_u128(v).value), FloatTy::F32 => Scalar::from_f32(Single::from_u128(v).value), FloatTy::F64 => Scalar::from_f64(Double::from_u128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => Scalar::from_f128(Quad::from_u128(v).value), }, // u8 -> char @@ -321,7 +321,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Low-level cast helper function. Converts an apfloat `f` into int or float types. fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance> where - F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>, + F: Float + + Into<Scalar<M::Provenance>> + + FloatConvert<Half> + + FloatConvert<Single> + + FloatConvert<Double> + + FloatConvert<Quad>, { use rustc_type_ir::TyKind::*; @@ -358,10 +363,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // float -> float Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(adjust_nan(self, f, f.convert(&mut false).value)), FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)), FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + Scalar::from_f128(adjust_nan(self, f, f.convert(&mut false).value)) + } }, // That's it. _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 32a047a9363..f884f996927 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -585,6 +585,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee) ), + // RFC 3543 + // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` + gated!( + patchable_function_entry, Normal, template!(List: "prefix_nops = m, entry_nops = n"), ErrorPreceding, + EncodeCrossCrate::Yes, experimental!(patchable_function_entry) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f4e20328814..ad6f7da8937 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -563,6 +563,8 @@ declare_features! ( (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), + /// Allows specifying nop padding on functions for dynamic patching. + (unstable, patchable_function_entry, "CURRENT_RUSTC_VERSION", Some(123115)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e7892f17660..18aff6a4d5a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -70,10 +70,10 @@ pub fn provide(providers: &mut Providers) { predicates_of: predicates_of::predicates_of, predicates_defined_on, explicit_predicates_of: predicates_of::explicit_predicates_of, - super_predicates_of: predicates_of::super_predicates_of, - implied_predicates_of: predicates_of::implied_predicates_of, - super_predicates_that_define_assoc_item: - predicates_of::super_predicates_that_define_assoc_item, + explicit_super_predicates_of: predicates_of::explicit_super_predicates_of, + explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of, + explicit_supertraits_containing_assoc_item: + predicates_of::explicit_supertraits_containing_assoc_item, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, @@ -691,14 +691,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::Trait(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().trait_def(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); tcx.ensure().associated_items(def_id); } hir::ItemKind::TraitAlias(..) => { tcx.ensure().generics_of(def_id); - tcx.at(it.span).implied_predicates_of(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_implied_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); } hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 3421c8da4e9..8ba524e72eb 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -519,21 +519,21 @@ pub(super) fn explicit_predicates_of<'tcx>( /// Ensures that the super-predicates of the trait with a `DefId` /// of `trait_def_id` are lowered and stored. This also ensures that /// the transitive super-predicates are lowered. -pub(super) fn super_predicates_of( +pub(super) fn explicit_super_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly) } -pub(super) fn super_predicates_that_define_assoc_item( +pub(super) fn explicit_supertraits_containing_assoc_item( tcx: TyCtxt<'_>, (trait_def_id, assoc_name): (DefId, Ident), ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name)) } -pub(super) fn implied_predicates_of( +pub(super) fn explicit_implied_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { @@ -560,7 +560,7 @@ pub(super) fn implied_predicates_with_filter( // if `assoc_name` is None, then the query should've been redirected to an // external provider assert!(matches!(filter, PredicateFilter::SelfThatDefines(_))); - return tcx.super_predicates_of(trait_def_id); + return tcx.explicit_super_predicates_of(trait_def_id); }; let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else { @@ -601,7 +601,7 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).super_predicates_of(bound.def_id()); + tcx.at(span).explicit_super_predicates_of(bound.def_id()); } } } @@ -611,7 +611,7 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).implied_predicates_of(bound.def_id()); + tcx.at(span).explicit_implied_predicates_of(bound.def_id()); } } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index abc3bb838db..f953e324162 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1760,7 +1760,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if let Some(assoc_item) = trait_defines_associated_item_named(def_id) { break Some((bound_vars.into_iter().collect(), assoc_item)); } - let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name)); + let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_name)); let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index ab4148faaab..24cf9f03fcd 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -275,10 +275,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { } // Get predicates implied by the trait, or only super predicates if we only care about self predicates. let predicates = match self.mode { - Filter::All => tcx.implied_predicates_of(data.def_id()), - Filter::OnlySelf => tcx.super_predicates_of(data.def_id()), + Filter::All => tcx.explicit_implied_predicates_of(data.def_id()), + Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()), Filter::OnlySelfThatDefines(ident) => { - tcx.super_predicates_that_define_assoc_item((data.def_id(), ident)) + tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident)) } }; @@ -420,7 +420,7 @@ pub fn transitive_bounds<'tcx>( /// A specialized variant of `elaborate` that only elaborates trait references that may /// define the given associated item with the name `assoc_name`. It uses the -/// `super_predicates_that_define_assoc_item` query to avoid enumerating super-predicates that +/// `explicit_supertraits_containing_assoc_item` query to avoid enumerating super-predicates that /// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or /// `T::Item` and helps to avoid cycle errors (see e.g. #35237). pub fn transitive_bounds_that_define_assoc_item<'tcx>( diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6ffc518097e..02322c9b282 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,8 +8,8 @@ use rustc_session::config::{ ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, - PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, - SymbolManglingVersion, WasiExecModel, + PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, + SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -813,6 +813,11 @@ fn test_unstable_options_tracking_hash() { tracked!(packed_bundled_libs, true); tracked!(panic_abort_tests, true); tracked!(panic_in_drop, PanicStrategy::Abort); + tracked!( + patchable_function_entry, + PatchableFunctionEntry::from_total_and_prefix_nops(10, 5) + .expect("total must be greater than or equal to prefix") + ); tracked!(plt, Some(true)); tracked!(polonius, Polonius::Legacy); tracked!(precise_enum_drop_elaboration, false); diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index aa1d94228ea..445dcd41e5d 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { { let direct_super_traits_iter = cx .tcx - .super_predicates_of(def_id) + .explicit_super_predicates_of(def_id) .predicates .into_iter() .filter_map(|(pred, _)| pred.as_trait_clause()); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 300dac442d5..17429ed061f 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -50,7 +50,7 @@ declare_lint! { /// All nested bodies (functions, enum discriminant, array length, consts) (expect for /// `const _: Ty = { ... }` in top-level module, which is still undecided) are checked. pub NON_LOCAL_DEFINITIONS, - Warn, + Allow, "checks for non-local definitions", report_in_external_macro } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index c9450142cd3..743ceb1ee6c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -211,8 +211,8 @@ provide! { tcx, def_id, other, cdata, explicit_predicates_of => { table } generics_of => { table } inferred_outlives_of => { table_defaulted_array } - super_predicates_of => { table } - implied_predicates_of => { table } + explicit_super_predicates_of => { table } + explicit_implied_predicates_of => { table } type_of => { table } type_alias_is_lazy => { cdata.root.tables.type_alias_is_lazy.get(cdata, def_id.index) } variances_of => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4bd2ec09a6e..957e578a08e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1431,8 +1431,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::Trait = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); - record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); + record!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id)); + record!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id)); let module_children = self.tcx.module_children_local(local_id); record_array!(self.tables.module_children_non_reexports[def_id] <- @@ -1440,8 +1440,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::TraitAlias = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); - record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); + record!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id)); + record!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id)); } if let DefKind::Trait | DefKind::Impl { .. } = def_kind { let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 87900c23d8d..5f729fa8e34 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -416,10 +416,10 @@ define_tables! { lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>, explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, generics_of: Table<DefIndex, LazyValue<ty::Generics>>, - super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, + explicit_super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, // As an optimization, we only store this for trait aliases, - // since it's identical to super_predicates_of for traits. - implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, + // since it's identical to explicit_super_predicates_of for traits. + explicit_implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>, variances_of: Table<DefIndex, LazyArray<ty::Variance>>, fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index c8f0d0795a3..3ddf889b63a 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -45,6 +45,32 @@ pub struct CodegenFnAttrs { /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be /// aligned to. pub alignment: Option<Align>, + /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around + /// the function entry. + pub patchable_function_entry: Option<PatchableFunctionEntry>, +} + +#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +pub struct PatchableFunctionEntry { + /// Nops to prepend to the function + prefix: u8, + /// Nops after entry, but before body + entry: u8, +} + +impl PatchableFunctionEntry { + pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self { + Self { prefix: config.prefix(), entry: config.entry() } + } + pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self { + Self { prefix, entry } + } + pub fn prefix(&self) -> u8 { + self.prefix + } + pub fn entry(&self) -> u8 { + self.entry + } } #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] @@ -121,6 +147,7 @@ impl CodegenFnAttrs { no_sanitize: SanitizerSet::empty(), instruction_set: None, alignment: None, + patchable_function_entry: None, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 230a44bcf24..86a415772de 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -646,6 +646,9 @@ rustc_queries! { } /// Returns the predicates written explicitly by the user. + /// + /// You should probably use `predicates_of` unless you're looking for + /// predicates with explicit spans for diagnostics purposes. query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -662,29 +665,32 @@ rustc_queries! { feedable } - /// Maps from the `DefId` of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + /// Maps from the `DefId` of a trait to the list of super-predicates of the trait, + /// *before* elaboration (so it doesn't contain transitive super-predicates). This + /// is a subset of the full list of predicates. We store these in a separate map + /// because we must evaluate them even during type conversion, often before the full + /// predicates are available (note that super-predicates must not be cyclic). + query explicit_super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - query implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + /// The predicates of the trait that are implied during elaboration. This is a + /// superset of the super-predicates of the trait, but a subset of the predicates + /// of the trait. For regular traits, this includes all super-predicates and their + /// associated type bounds. For trait aliases, currently, this includes all of the + /// predicates of the trait alias. + query explicit_implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the implied predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query - /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the - /// subset of super-predicates that reference traits that define the given associated type. - /// This is used to avoid cycles in resolving types like `T::Item`. - query super_predicates_that_define_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + /// The Ident is the name of an associated type.The query returns only the subset + /// of supertraits that define the given associated type. This is used to avoid + /// cycles in resolving type-dependent associated item paths like `T::Item`. + query explicit_supertraits_containing_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super traits of `{}` with associated type name `{}`", tcx.def_path_str(key.0), key.1 diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index adbb6cf2ddc..7437be7a74c 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -35,7 +35,7 @@ struct Elaborator<'tcx> { impl<'tcx> Elaborator<'tcx> { fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) { let super_predicates = - self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( + self.tcx.explicit_super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( |&(pred, _)| { let clause = pred.instantiate_supertrait(self.tcx, trait_ref); self.visited.insert(clause).then_some(clause) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4bac9396e59..ed1ec55bc8e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -342,12 +342,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn super_predicates_of( + fn explicit_super_predicates_of( self, def_id: DefId, ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> { ty::EarlyBinder::bind( - self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + self.explicit_super_predicates_of(def_id) + .instantiate_identity(self) + .predicates + .into_iter(), ) } @@ -2440,7 +2443,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.super_traits_of(trait_def_id).any(|trait_did| { + self.supertrait_def_ids(trait_def_id).any(|trait_did| { self.associated_items(trait_did) .filter_by_name_unhygienic(assoc_name.name) .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did)) @@ -2463,9 +2466,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used - /// to identify which traits may define a given associated type to help avoid cycle errors. - /// Returns a `DefId` iterator. - fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { + /// to identify which traits may define a given associated type to help avoid cycle errors, + /// and to make size estimates for vtable layout computation. + pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; @@ -2473,7 +2476,7 @@ impl<'tcx> TyCtxt<'tcx> { iter::from_fn(move || -> Option<DefId> { let trait_did = stack.pop()?; - let generic_predicates = self.super_predicates_of(trait_did); + let generic_predicates = self.explicit_super_predicates_of(trait_did); for (predicate, _) in generic_predicates.predicates { if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index dc3c84f9e43..466c3b93f8e 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -3,8 +3,6 @@ use std::fmt; use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; use rustc_ast::Mutability; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::DefId; use rustc_macros::HashStable; #[derive(Clone, Copy, PartialEq, HashStable)] @@ -42,45 +40,12 @@ impl<'tcx> fmt::Debug for VtblEntry<'tcx> { impl<'tcx> TyCtxt<'tcx> { pub const COMMON_VTABLE_ENTRIES: &'tcx [VtblEntry<'tcx>] = &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign]; - - pub fn supertrait_def_ids(self, trait_def_id: DefId) -> SupertraitDefIds<'tcx> { - SupertraitDefIds { - tcx: self, - stack: vec![trait_def_id], - visited: Some(trait_def_id).into_iter().collect(), - } - } } pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0; pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1; pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2; -pub struct SupertraitDefIds<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<DefId>, - visited: FxHashSet<DefId>, -} - -impl Iterator for SupertraitDefIds<'_> { - type Item = DefId; - - fn next(&mut self) -> Option<DefId> { - let def_id = self.stack.pop()?; - let predicates = self.tcx.super_predicates_of(def_id); - let visited = &mut self.visited; - self.stack.extend( - predicates - .predicates - .iter() - .filter_map(|(pred, _)| pred.as_trait_clause()) - .map(|trait_ref| trait_ref.def_id()) - .filter(|&super_def_id| visited.insert(super_def_id)), - ); - Some(def_id) - } -} - // Note that we don't have access to a self type here, this has to be purely based on the trait (and // supertrait) definitions. That means we can't call into the same vtable_entries code since that // returns a specific instantiation (e.g., with Vacant slots when bounds aren't satisfied). The goal diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index c1d645aa42c..476969a1bd7 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -189,38 +189,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let initializer_span = this.thir[*initializer].span; let scope = (*init_scope, source_info); - let failure = unpack!( - block = this.in_scope(scope, *lint_level, |this| { - this.declare_bindings( - visibility_scope, - remainder_span, - pattern, - None, - Some((Some(&destination), initializer_span)), - ); - this.visit_primary_bindings( - pattern, - UserTypeProjections::none(), - &mut |this, _, _, node, span, _, _| { - this.storage_live_binding( - block, - node, - span, - OutsideGuard, - true, - ); - }, - ); - this.ast_let_else( - block, - *initializer, - initializer_span, - *else_block, - &last_remainder_scope, - pattern, - ) - }) - ); + let failure_and_block = this.in_scope(scope, *lint_level, |this| { + this.declare_bindings( + visibility_scope, + remainder_span, + pattern, + None, + Some((Some(&destination), initializer_span)), + ); + this.visit_primary_bindings( + pattern, + UserTypeProjections::none(), + &mut |this, _, _, node, span, _, _| { + this.storage_live_binding(block, node, span, OutsideGuard, true); + }, + ); + let else_block_span = this.thir[*else_block].span; + let (matching, failure) = + this.in_if_then_scope(last_remainder_scope, else_block_span, |this| { + this.lower_let_expr( + block, + *initializer, + pattern, + None, + initializer_span, + false, + true, + ) + }); + matching.and(failure) + }); + let failure = unpack!(block = failure_and_block); this.cfg.goto(failure, source_info, failure_entry); if let Some(source_scope) = visibility_scope { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 932406fd1aa..6d52c308237 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -21,6 +21,7 @@ use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; +use util::visit_bindings; // helper functions, broken out by category: mod simplify; @@ -146,6 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(args.variable_source_info.scope), args.variable_source_info.span, args.declare_let_bindings, + false, ), _ => { let mut block = block; @@ -314,13 +316,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let match_start_span = span.shrink_to_lo().to(scrutinee_span); - let fake_borrow_temps = self.lower_match_tree( + // The set of places that we are creating fake borrows of. If there are no match guards then + // we don't need any fake borrows, so don't track them. + let fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { + util::collect_fake_borrows(self, &candidates, scrutinee_span, scrutinee_place.base()) + } else { + Vec::new() + }; + + self.lower_match_tree( block, scrutinee_span, &scrutinee_place, match_start_span, - match_has_guard, &mut candidates, + false, ); self.lower_match_arms( @@ -375,89 +385,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .collect() } - /// Create the decision tree for the match expression, starting from `block`. - /// - /// Modifies `candidates` to store the bindings and type ascriptions for - /// that candidate. - /// - /// Returns the places that need fake borrows because we bind or test them. - fn lower_match_tree<'pat>( - &mut self, - block: BasicBlock, - scrutinee_span: Span, - scrutinee_place_builder: &PlaceBuilder<'tcx>, - match_start_span: Span, - match_has_guard: bool, - candidates: &mut [&mut Candidate<'pat, 'tcx>], - ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { - // The set of places that we are creating fake borrows of. If there are no match guards then - // we don't need any fake borrows, so don't track them. - let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { - util::collect_fake_borrows( - self, - candidates, - scrutinee_span, - scrutinee_place_builder.base(), - ) - } else { - Vec::new() - }; - - // See the doc comment on `match_candidates` for why we have an - // otherwise block. Match checking will ensure this is actually - // unreachable. - let otherwise_block = self.cfg.start_new_block(); - - // This will generate code to test scrutinee_place and - // branch to the appropriate arm block - self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); - - let source_info = self.source_info(scrutinee_span); - - // Matching on a `scrutinee_place` with an uninhabited type doesn't - // generate any memory reads by itself, and so if the place "expression" - // contains unsafe operations like raw pointer dereferences or union - // field projections, we wouldn't know to require an `unsafe` block - // around a `match` equivalent to `std::intrinsics::unreachable()`. - // See issue #47412 for this hole being discovered in the wild. - // - // HACK(eddyb) Work around the above issue by adding a dummy inspection - // of `scrutinee_place`, specifically by applying `ReadForMatch`. - // - // NOTE: ReadForMatch also checks that the scrutinee is initialized. - // This is currently needed to not allow matching on an uninitialized, - // uninhabited value. If we get never patterns, those will check that - // the place is initialized, and so this read would only be used to - // check safety. - let cause_matched_place = FakeReadCause::ForMatchedPlace(None); - - if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { - self.cfg.push_fake_read( - otherwise_block, - source_info, - cause_matched_place, - scrutinee_place, - ); - } - - self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); - - // Link each leaf candidate to the `pre_binding_block` of the next one. - let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; - - for candidate in candidates { - candidate.visit_leaves(|leaf_candidate| { - if let Some(ref mut prev) = previous_candidate { - assert!(leaf_candidate.false_edge_start_block.is_some()); - prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; - } - previous_candidate = Some(leaf_candidate); - }); - } - - fake_borrows - } - /// Lower the bindings, guards and arm bodies of a `match` expression. /// /// The decision tree should have already been created @@ -728,59 +655,53 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { set_match_place: bool, ) -> BlockAnd<()> { let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self); - let fake_borrow_temps = self.lower_match_tree( - block, - irrefutable_pat.span, - &initializer, - irrefutable_pat.span, - false, - &mut [&mut candidate], - ); // For matches and function arguments, the place that is being matched // can be set when creating the variables. But the place for // let PATTERN = ... might not even exist until we do the assignment. // so we set it here instead. if set_match_place { - let mut next = Some(&candidate); - while let Some(candidate_ref) = next.take() { - for binding in &candidate_ref.extra_data.bindings { + // `try_to_place` may fail if it is unable to resolve the given `PlaceBuilder` inside a + // closure. In this case, we don't want to include a scrutinee place. + // `scrutinee_place_builder` will fail for destructured assignments. This is because a + // closure only captures the precise places that it will read and as a result a closure + // may not capture the entire tuple/struct and rather have individual places that will + // be read in the final MIR. + // Example: + // ``` + // let foo = (0, 1); + // let c = || { + // let (v1, v2) = foo; + // }; + // ``` + if let Some(place) = initializer.try_to_place(self) { + visit_bindings(&[&mut candidate], |binding: &Binding<'_>| { let local = self.var_local_id(binding.var_id, OutsideGuard); - // `try_to_place` may fail if it is unable to resolve the given - // `PlaceBuilder` inside a closure. In this case, we don't want to include - // a scrutinee place. `scrutinee_place_builder` will fail for destructured - // assignments. This is because a closure only captures the precise places - // that it will read and as a result a closure may not capture the entire - // tuple/struct and rather have individual places that will be read in the - // final MIR. - // Example: - // ``` - // let foo = (0, 1); - // let c = || { - // let (v1, v2) = foo; - // }; - // ``` - if let Some(place) = initializer.try_to_place(self) { - let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref mut match_place, _)), - .. - })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() - else { - bug!("Let binding to non-user variable.") - }; + if let LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref mut match_place, _)), + .. + })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() + { *match_place = Some(place); - } - } - // All of the subcandidates should bind the same locals, so we - // only visit the first one. - next = candidate_ref.subcandidates.get(0) + } else { + bug!("Let binding to non-user variable.") + }; + }); } } + self.lower_match_tree( + block, + irrefutable_pat.span, + &initializer, + irrefutable_pat.span, + &mut [&mut candidate], + false, + ); self.bind_pattern( self.source_info(irrefutable_pat.span), candidate, - fake_borrow_temps.as_slice(), + &[], irrefutable_pat.span, None, false, @@ -1306,6 +1227,79 @@ pub(crate) struct ArmHasGuard(pub(crate) bool); // Main matching algorithm impl<'a, 'tcx> Builder<'a, 'tcx> { + /// The entrypoint of the matching algorithm. Create the decision tree for the match expression, + /// starting from `block`. + /// + /// Modifies `candidates` to store the bindings and type ascriptions for + /// that candidate. + /// + /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`) + /// or not (for `let` and `match`). In the refutable case we return the block to which we branch + /// on failure. + fn lower_match_tree<'pat>( + &mut self, + block: BasicBlock, + scrutinee_span: Span, + scrutinee_place_builder: &PlaceBuilder<'tcx>, + match_start_span: Span, + candidates: &mut [&mut Candidate<'pat, 'tcx>], + refutable: bool, + ) -> BasicBlock { + // See the doc comment on `match_candidates` for why we have an otherwise block. + let otherwise_block = self.cfg.start_new_block(); + + // This will generate code to test scrutinee_place and branch to the appropriate arm block + self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); + + // Link each leaf candidate to the `false_edge_start_block` of the next one. + let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; + for candidate in candidates { + candidate.visit_leaves(|leaf_candidate| { + if let Some(ref mut prev) = previous_candidate { + assert!(leaf_candidate.false_edge_start_block.is_some()); + prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; + } + previous_candidate = Some(leaf_candidate); + }); + } + + if refutable { + // In refutable cases there's always at least one candidate, and we want a false edge to + // the failure block. + previous_candidate.as_mut().unwrap().next_candidate_start_block = Some(otherwise_block) + } else { + // Match checking ensures `otherwise_block` is actually unreachable in irrefutable + // cases. + let source_info = self.source_info(scrutinee_span); + + // Matching on a scrutinee place of an uninhabited type doesn't generate any memory + // reads by itself, and so if the place is uninitialized we wouldn't know. In order to + // disallow the following: + // ```rust + // let x: !; + // match x {} + // ``` + // we add a dummy read on the place. + // + // NOTE: If we require never patterns for empty matches, those will check that the place + // is initialized, and so this read would no longer be needed. + let cause_matched_place = FakeReadCause::ForMatchedPlace(None); + + if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { + self.cfg.push_fake_read( + otherwise_block, + source_info, + cause_matched_place, + scrutinee_place, + ); + } + + self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); + } + + otherwise_block + } + /// The main match algorithm. It begins with a set of candidates /// `candidates` and has the job of generating code to determine /// which of these candidates, if any, is the correct one. The @@ -1998,52 +1992,50 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> { /// If the bindings have already been declared, set `declare_bindings` to - /// `false` to avoid duplicated bindings declaration. Used for if-let guards. + /// `false` to avoid duplicated bindings declaration; used for if-let guards. pub(crate) fn lower_let_expr( &mut self, mut block: BasicBlock, expr_id: ExprId, pat: &Pat<'tcx>, source_scope: Option<SourceScope>, - span: Span, + scope_span: Span, declare_bindings: bool, + storages_alive: bool, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; - let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); - let wildcard = Pat::wildcard_from_ty(pat.ty); - let mut guard_candidate = Candidate::new(expr_place_builder.clone(), pat, false, self); - let mut otherwise_candidate = - Candidate::new(expr_place_builder.clone(), &wildcard, false, self); - let fake_borrow_temps = self.lower_match_tree( + let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); + let mut candidate = Candidate::new(scrutinee.clone(), pat, false, self); + let otherwise_block = self.lower_match_tree( block, + expr_span, + &scrutinee, pat.span, - &expr_place_builder, - pat.span, - false, - &mut [&mut guard_candidate, &mut otherwise_candidate], + &mut [&mut candidate], + true, ); - let expr_place = expr_place_builder.try_to_place(self); - let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); - let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); - self.break_for_else(otherwise_post_guard_block, self.source_info(expr_span)); + + self.break_for_else(otherwise_block, self.source_info(expr_span)); if declare_bindings { - self.declare_bindings(source_scope, pat.span.to(span), pat, None, opt_expr_place); + let expr_place = scrutinee.try_to_place(self); + let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); + self.declare_bindings(source_scope, pat.span.to(scope_span), pat, None, opt_expr_place); } - let post_guard_block = self.bind_pattern( + let success = self.bind_pattern( self.source_info(pat.span), - guard_candidate, - fake_borrow_temps.as_slice(), + candidate, + &[], expr_span, None, - false, + storages_alive, ); // If branch coverage is enabled, record this branch. - self.visit_coverage_conditional_let(pat, post_guard_block, otherwise_post_guard_block); + self.visit_coverage_conditional_let(pat, success, otherwise_block); - post_guard_block.unit() + success.unit() } /// Initializes each of the bindings from the candidate by @@ -2091,14 +2083,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return self.cfg.start_new_block(); } - self.ascribe_types( - block, - parent_data - .iter() - .flat_map(|d| &d.ascriptions) - .cloned() - .chain(candidate.extra_data.ascriptions), - ); + let ascriptions = parent_data + .iter() + .flat_map(|d| &d.ascriptions) + .cloned() + .chain(candidate.extra_data.ascriptions); + let bindings = + parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); + + self.ascribe_types(block, ascriptions); // rust-lang/rust#27282: The `autoref` business deserves some // explanation here. @@ -2185,12 +2178,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { && let Some(guard) = arm.guard { let tcx = self.tcx; - let bindings = - parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); - let guard_frame = - GuardFrame { locals: bindings.map(|b| GuardFrameLocal::new(b.var_id)).collect() }; + let guard_frame = GuardFrame { + locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(), + }; debug!("entering guard building context: {:?}", guard_frame); self.guard_context.push(guard_frame); @@ -2263,11 +2255,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = parent_data - .iter() - .flat_map(|d| &d.bindings) - .chain(&candidate.extra_data.bindings) - .filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); + let by_value_bindings = + bindings.filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { @@ -2291,7 +2280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.bind_matched_candidate_for_arm_body( block, schedule_drops, - parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings), + bindings, storages_alive, ); block @@ -2493,55 +2482,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!(?locals); self.var_indices.insert(var_id, locals); } - - pub(crate) fn ast_let_else( - &mut self, - mut block: BasicBlock, - init_id: ExprId, - initializer_span: Span, - else_block: BlockId, - let_else_scope: ®ion::Scope, - pattern: &Pat<'tcx>, - ) -> BlockAnd<BasicBlock> { - let else_block_span = self.thir[else_block].span; - let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| { - let scrutinee = unpack!(block = this.lower_scrutinee(block, init_id, initializer_span)); - let pat = Pat { ty: pattern.ty, span: else_block_span, kind: PatKind::Wild }; - let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this); - let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this); - let fake_borrow_temps = this.lower_match_tree( - block, - initializer_span, - &scrutinee, - pattern.span, - false, - &mut [&mut candidate, &mut wildcard], - ); - // This block is for the matching case - let matching = this.bind_pattern( - this.source_info(pattern.span), - candidate, - fake_borrow_temps.as_slice(), - initializer_span, - None, - true, - ); - // This block is for the failure case - let failure = this.bind_pattern( - this.source_info(else_block_span), - wildcard, - fake_borrow_temps.as_slice(), - initializer_span, - None, - true, - ); - - // If branch coverage is enabled, record this branch. - this.visit_coverage_conditional_let(pattern, matching, failure); - - this.break_for_else(failure, this.source_info(initializer_span)); - matching.unit() - }); - matching.and(failure) - } } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 630d0b9438d..3bec154e1df 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; @@ -269,18 +271,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { } } -pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { - cx: &'a mut Builder<'b, 'tcx>, - /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from - /// bindings inside deref patterns. - scrutinee_base: PlaceBase, - /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest - /// borrow (i.e. Deep > Shallow). - /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are - /// dereferences are also borrowed with the same of stronger borrow kind. - fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>, -} - /// Determine the set of places that have to be stable across match guards. /// /// Returns a list of places that need a fake borrow along with a local to store it. @@ -344,6 +334,18 @@ pub(super) fn collect_fake_borrows<'tcx>( .collect() } +pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { + cx: &'a mut Builder<'b, 'tcx>, + /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from + /// bindings inside deref patterns. + scrutinee_base: PlaceBase, + /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest + /// borrow (i.e. Deep > Shallow). + /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are + /// dereferences are also borrowed with the same of stronger borrow kind. + fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>, +} + impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // Fake borrow this place and its dereference prefixes. fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) { @@ -457,6 +459,57 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } +/// Visit all the bindings of these candidates. Because or-alternatives bind the same variables, we +/// only explore the first one of each or-pattern. +pub(super) fn visit_bindings<'tcx>( + candidates: &[&mut Candidate<'_, 'tcx>], + f: impl FnMut(&Binding<'tcx>), +) { + let mut visitor = BindingsVisitor { f, phantom: PhantomData }; + for candidate in candidates.iter() { + visitor.visit_candidate(candidate); + } +} + +pub(super) struct BindingsVisitor<'tcx, F> { + f: F, + phantom: PhantomData<&'tcx ()>, +} + +impl<'tcx, F> BindingsVisitor<'tcx, F> +where + F: FnMut(&Binding<'tcx>), +{ + fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { + for binding in &candidate.extra_data.bindings { + (self.f)(binding) + } + for match_pair in &candidate.match_pairs { + self.visit_match_pair(match_pair); + } + } + + fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) { + for binding in &flat_pat.extra_data.bindings { + (self.f)(binding) + } + for match_pair in &flat_pat.match_pairs { + self.visit_match_pair(match_pair); + } + } + + fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { + if let TestCase::Or { pats, .. } = &match_pair.test_case { + // All the or-alternatives should bind the same locals, so we only visit the first one. + self.visit_flat_pat(&pats[0]) + } else { + for subpair in &match_pair.subpairs { + self.visit_match_pair(subpair); + } + } + } +} + #[must_use] pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { match ref_mutability { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 0a5fc697d03..07482d0571a 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt, TypeFlags}; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -306,6 +306,16 @@ impl<'tcx> Inliner<'tcx> { InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { return Err("instance without MIR (intrinsic / virtual)"); } + + // FIXME(#127030): `ConstParamHasTy` has bad interactions with + // the drop shim builder, which does not evaluate predicates in + // the correct param-env for types being dropped. Stall resolving + // the MIR for this instance until all of its const params are + // substituted. + InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => { + return Err("still needs substitution"); + } + // This cannot result in an immediate cycle since the callee MIR is a shim, which does // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 0cef8d9f4bc..3447b39fa5b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -668,8 +668,9 @@ where { let cx = ecx.cx(); let mut requirements = vec![]; - requirements - .extend(cx.super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args)); + requirements.extend( + cx.explicit_super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args), + ); // FIXME(associated_const_equality): Also add associated consts to // the requirements here. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e0c70884fee..3cdc20b6c65 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3432,8 +3432,9 @@ impl<'a> Parser<'a> { } } let capture_clause = self.parse_capture_clause()?; + let decl_span = lo.to(self.prev_token.span); let (attrs, body) = self.parse_inner_attrs_and_block()?; - let kind = ExprKind::Gen(capture_clause, body, kind); + let kind = ExprKind::Gen(capture_clause, body, kind, decl_span); Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs)) } @@ -4022,7 +4023,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Match(_, _, _) | ExprKind::Closure(_) | ExprKind::Block(_, _) - | ExprKind::Gen(_, _, _) + | ExprKind::Gen(_, _, _, _) | ExprKind::TryBlock(_) | ExprKind::Underscore | ExprKind::Path(_, _) diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index da4435ebebe..6dd8eaf7e67 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -30,7 +30,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::bug; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc}; use rustc_middle::query::Providers; @@ -178,7 +178,15 @@ impl<'tcx> ReachableContext<'tcx> { if !self.any_library { // If we are building an executable, only explicitly extern // types need to be exported. - if has_custom_linkage(self.tcx, search_item) { + let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() { + self.tcx.codegen_fn_attrs(search_item) + } else { + CodegenFnAttrs::EMPTY + }; + let is_extern = codegen_attrs.contains_extern_indicator(); + let std_internal = + codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); + if is_extern || std_internal { self.reachable_symbols.insert(search_item); } } else { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1bca5602a4e..80619c59cc3 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -334,7 +334,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { None => closure_def, } } - ExprKind::Gen(_, _, _) => { + ExprKind::Gen(_, _, _, _) => { self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2d38ad37133..41c99f7edee 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2965,8 +2965,9 @@ pub(crate) mod dep_tracking { CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, - SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, + PatchableFunctionEntry, Polonius, RemapPathScopeComponents, ResolveDocLinks, + SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, + WasiExecModel, }; use crate::lint; use crate::utils::NativeLib; @@ -3073,6 +3074,7 @@ pub(crate) mod dep_tracking { OomStrategy, LanguageIdentifier, NextSolverConfig, + PatchableFunctionEntry, Polonius, InliningThreshold, FunctionReturn, @@ -3250,6 +3252,35 @@ impl DumpMonoStatsFormat { } } +/// `-Z patchable-function-entry` representation - how many nops to put before and after function +/// entry. +#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] +pub struct PatchableFunctionEntry { + /// Nops before the entry + prefix: u8, + /// Nops after the entry + entry: u8, +} + +impl PatchableFunctionEntry { + pub fn from_total_and_prefix_nops( + total_nops: u8, + prefix_nops: u8, + ) -> Option<PatchableFunctionEntry> { + if total_nops < prefix_nops { + None + } else { + Some(Self { prefix: prefix_nops, entry: total_nops - prefix_nops }) + } + } + pub fn prefix(&self) -> u8 { + self.prefix + } + pub fn entry(&self) -> u8 { + self.entry + } +} + /// `-Zpolonius` values, enabling the borrow checker polonius analysis, and which version: legacy, /// or future prototype. #[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9a10adeb6d1..80f7ca544f3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -379,6 +379,7 @@ mod desc { pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`"; + pub const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)"; pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; @@ -734,6 +735,32 @@ mod parse { true } + pub(crate) fn parse_patchable_function_entry( + slot: &mut PatchableFunctionEntry, + v: Option<&str>, + ) -> bool { + let mut total_nops = 0; + let mut prefix_nops = 0; + + if !parse_number(&mut total_nops, v) { + let parts = v.and_then(|v| v.split_once(',')).unzip(); + if !parse_number(&mut total_nops, parts.0) { + return false; + } + if !parse_number(&mut prefix_nops, parts.1) { + return false; + } + } + + if let Some(pfe) = + PatchableFunctionEntry::from_total_and_prefix_nops(total_nops, prefix_nops) + { + *slot = pfe; + return true; + } + false + } + pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool { match v { Some("panic") => *slot = OomStrategy::Panic, @@ -1859,6 +1886,8 @@ options! { "panic strategy for panics in drops"), parse_only: bool = (false, parse_bool, [UNTRACKED], "parse only; do not compile, assemble, or link (default: no)"), + patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED], + "nop padding at function entry"), plt: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether to use the PLT when calling into shared libraries; only has effect for PIC code on systems with ELF binaries diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 1e0a60bc371..1230667ee91 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index dde5e30c3d0..e23f4289e98 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -228,6 +228,46 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } + fn get_attrs_by_path( + &self, + def_id: stable_mir::DefId, + attr: &[stable_mir::Symbol], + ) -> Vec<stable_mir::crate_def::Attribute> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let did = tables[def_id]; + let attr_name: Vec<_> = + attr.iter().map(|seg| rustc_span::symbol::Symbol::intern(&seg)).collect(); + tcx.get_attrs_by_path(did, &attr_name) + .map(|attribute| { + let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + }) + .collect() + } + + fn get_all_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let did = tables[def_id]; + let filter_fn = move |a: &&rustc_ast::ast::Attribute| { + matches!(a.kind, rustc_ast::ast::AttrKind::Normal(_)) + }; + let attrs_iter = if let Some(did) = did.as_local() { + tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + } else { + tcx.item_attrs(did).iter().filter(filter_fn) + }; + attrs_iter + .map(|attribute| { + let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + }) + .collect() + } + fn span_to_string(&self, span: stable_mir::ty::Span) -> String { let tables = self.0.borrow(); tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span]) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6d4a8c29bc9..3b6147c4c0f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -768,6 +768,7 @@ symbols! { enable, encode, end, + entry_nops, enumerate_method, env, env_CFG_RELEASE: env!("CFG_RELEASE"), @@ -1383,6 +1384,7 @@ symbols! { passes, pat, pat_param, + patchable_function_entry, path, pattern_complexity, pattern_parentheses, @@ -1421,6 +1423,7 @@ symbols! { prefetch_read_instruction, prefetch_write_data, prefetch_write_instruction, + prefix_nops, preg, prelude, prelude_import, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 4d10d33fa6e..f1611bd049d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -187,7 +187,7 @@ fn predicates_reference_self( ) -> SmallVec<[Span; 1]> { let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); let predicates = if supertraits_only { - tcx.super_predicates_of(trait_def_id) + tcx.explicit_super_predicates_of(trait_def_id) } else { tcx.predicates_of(trait_def_id) }; @@ -256,7 +256,7 @@ fn super_predicates_have_non_lifetime_binders( if !tcx.features().non_lifetime_binders { return SmallVec::new(); } - tcx.super_predicates_of(trait_def_id) + tcx.explicit_super_predicates_of(trait_def_id) .predicates .iter() .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(*span)) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8c5dc88184c..9508a3e8e15 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -574,7 +574,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check supertraits hold. This is so that their associated type bounds // will be checked in the code below. for super_trait in tcx - .super_predicates_of(trait_predicate.def_id()) + .explicit_super_predicates_of(trait_predicate.def_id()) .instantiate(tcx, trait_predicate.trait_ref.args) .predicates .into_iter() diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index f132e36468a..951af4b0920 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -128,7 +128,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { } // Get components of trait alias. - let predicates = tcx.super_predicates_of(trait_ref.def_id()); + let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id()); debug!(?predicates); let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 017b0a45d1f..e54ced85dee 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -117,7 +117,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); let mut direct_super_traits_iter = tcx - .super_predicates_of(inner_most_trait_ref.def_id()) + .explicit_super_predicates_of(inner_most_trait_ref.def_id()) .predicates .into_iter() .filter_map(move |(pred, _)| { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b89ea30fc34..6665158c7cd 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -209,8 +209,7 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; - // FIXME: Rename this so it's obvious it's only *immediate* super predicates. - fn super_predicates_of( + fn explicit_super_predicates_of( self, def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 44dbf549c1a..5f2d9b96c73 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -6,6 +6,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; +use crate::crate_def::Attribute; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::{BinOp, Body, Place, UnOp}; @@ -55,6 +56,15 @@ pub trait Context { /// Returns the name of given `DefId` fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; + /// Return attributes with the given attribute name. + /// + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + fn get_attrs_by_path(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>; + + /// Get all attributes of a definition. + fn get_all_attrs(&self, def_id: DefId) -> Vec<Attribute>; + /// Returns printable, human readable form of `Span` fn span_to_string(&self, span: Span) -> String; diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 67752a5e629..d9b987c28a2 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -50,6 +50,21 @@ pub trait CrateDef { let def_id = self.def_id(); with(|cx| cx.span_of_an_item(def_id)) } + + /// Return attributes with the given attribute name. + /// + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + fn attrs_by_path(&self, attr: &[Symbol]) -> Vec<Attribute> { + let def_id = self.def_id(); + with(|cx| cx.get_attrs_by_path(def_id, attr)) + } + + /// Return all attributes of this definition. + fn all_attrs(&self) -> Vec<Attribute> { + let def_id = self.def_id(); + with(|cx| cx.get_all_attrs(def_id)) + } } /// A trait that can be used to retrieve a definition's type. @@ -69,6 +84,28 @@ pub trait CrateDefType: CrateDef { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Attribute { + value: String, + span: Span, +} + +impl Attribute { + pub fn new(value: String, span: Span) -> Attribute { + Attribute { value, span } + } + + /// Get the span of this attribute. + pub fn span(&self) -> Span { + self.span + } + + /// Get the string representation of this attribute. + pub fn as_str(&self) -> &str { + &self.value + } +} + macro_rules! crate_def { ( $(#[$attr:meta])* $vis:vis $name:ident $(;)? |
