| author | bors <bors@rust-lang.org> 2026-07-05 20:37:27 UTC |
| committer | bors <bors@rust-lang.org> 2026-07-05 20:37:27 UTC |
| log | 3659db0d3e2cd634c766fcda79ed118eca31a9fd |
| tree | ef148ffa7c8fa747f215faefd1547de7cc1d8827 |
| parent | 1c02d9026c9da54ef3323436f0ed0f8dd091d128 |
| parent | 9f3f1175689eafcca858199673c0c4943fd2a98b |
Rollup of 19 pull requests
Successful merges:
- rust-lang/rust#158692 (Add release notes for 1.96.1)
- rust-lang/rust#134021 (Implement `IntoIterator` for `[&[mut]] Box<[T; N], A>`)
- rust-lang/rust#155932 (MIR Call terminator: evaluate destination place before arguments)
- rust-lang/rust#155989 (Update `transmute_copy` to ub_checks and `?Sized`)
- rust-lang/rust#156777 (Add -Zautodiff_post_passes flag to limit which llvm passes to run after enzyme to make autodiff tests more robust)
- rust-lang/rust#157151 (JSON target specs: remove 'x86-softfloat' compatibility alias)
- rust-lang/rust#157835 (expand free alias types in the auto-trait orphan check)
- rust-lang/rust#157857 (Stabilize `#[my_macro] mod foo;` (part of `proc_macro_hygiene`))
- rust-lang/rust#158434 (delegation: refactor AST -> HIR lowering)
- rust-lang/rust#158552 (make some tidy errors around python easier to understand)
- rust-lang/rust#158624 (borrowck: Introduce BlameConstraint::to_obligation_cause_from_path())
- rust-lang/rust#158704 (Optimize `ArrayChunks::try_rfold` with `DoubleEndedIterator::next_chunk_back`)
- rust-lang/rust#158711 (library: Comment on libtest's dicey internal soundness)
- rust-lang/rust#158751 (rustdoc: Fix crash when trying to inline foreign item which cannot have attributes)
- rust-lang/rust#158539 (Move `SizeHint` and `IoHandle` to `core::io`)
- rust-lang/rust#158659 (refactor the normalization in `coerce_shared_info`)
- rust-lang/rust#158689 (resolver: don't use `Finalize` when resolving visibilities during AST expansion)
- rust-lang/rust#158698 (Update TypeVisitable implementation)
- rust-lang/rust#158706 (Tweaks to MIR building scope API)94 files changed, 2310 insertions(+), 1820 deletions(-)
RELEASES.md+9| ... | ... | @@ -1,3 +1,12 @@ |
| 1 | Version 1.96.1 (2026-06-30) | |
| 2 | =========================== | |
| 3 | ||
| 4 | <a id="1.96.1"></a> | |
| 5 | ||
| 6 | - [Cargo: fix timeout/retry behavior](https://github.com/rust-lang/cargo/pull/17131) | |
| 7 | - [Cargo: apply patches for CVE-2025-15661, CVE-2026-55199, and CVE-2026-55200 to libssh2](https://github.com/rust-lang/cargo/pull/17140) | |
| 8 | - [rustc: fix miscompilation in MIR optimization](https://github.com/rust-lang/rust/pull/158214) | |
| 9 | ||
| 1 | 10 | Version 1.96.0 (2026-05-28) |
| 2 | 11 | ========================== |
| 3 | 12 |
compiler/rustc_ast_lowering/src/delegation.rs deleted-871| ... | ... | @@ -1,871 +0,0 @@ |
| 1 | //! This module implements expansion of delegation items with early resolved paths. | |
| 2 | //! It includes a delegation to a free functions: | |
| 3 | //! | |
| 4 | //! ```ignore (illustrative) | |
| 5 | //! reuse module::name { target_expr_template } | |
| 6 | //! ``` | |
| 7 | //! | |
| 8 | //! And delegation to a trait methods: | |
| 9 | //! | |
| 10 | //! ```ignore (illustrative) | |
| 11 | //! reuse <Type as Trait>::name { target_expr_template } | |
| 12 | //! ``` | |
| 13 | //! | |
| 14 | //! After expansion for both cases we get: | |
| 15 | //! | |
| 16 | //! ```ignore (illustrative) | |
| 17 | //! fn name( | |
| 18 | //! arg0: InferDelegation(sig_id, Input(0)), | |
| 19 | //! arg1: InferDelegation(sig_id, Input(1)), | |
| 20 | //! ..., | |
| 21 | //! argN: InferDelegation(sig_id, Input(N)), | |
| 22 | //! ) -> InferDelegation(sig_id, Output) { | |
| 23 | //! callee_path(target_expr_template(arg0), arg1, ..., argN) | |
| 24 | //! } | |
| 25 | //! ``` | |
| 26 | //! | |
| 27 | //! Where `callee_path` is a path in delegation item e.g. `<Type as Trait>::name`. | |
| 28 | //! `sig_id` is a id of item from which the signature is inherited. It may be a delegation | |
| 29 | //! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise. | |
| 30 | //! | |
| 31 | //! Since we do not have a proper way to obtain function type information by path resolution | |
| 32 | //! in AST, we mark each function parameter type as `InferDelegation` and inherit it during | |
| 33 | //! HIR ty lowering. | |
| 34 | //! | |
| 35 | //! Similarly generics, predicates and header are set to the "default" values. | |
| 36 | //! In case of discrepancy with callee function the `UnsupportedDelegation` error will | |
| 37 | //! also be emitted during HIR ty lowering. | |
| 38 | ||
| 39 | use std::iter; | |
| 40 | use std::ops::ControlFlow; | |
| 41 | ||
| 42 | use ast::visit::Visitor; | |
| 43 | use hir::def::{DefKind, Res}; | |
| 44 | use hir::{BodyId, HirId}; | |
| 45 | use rustc_abi::ExternAbi; | |
| 46 | use rustc_ast as ast; | |
| 47 | use rustc_ast::node_id::NodeMap; | |
| 48 | use rustc_ast::*; | |
| 49 | use rustc_data_structures::fx::FxHashSet; | |
| 50 | use rustc_hir::attrs::{AttributeKind, InlineAttr}; | |
| 51 | use rustc_hir::{self as hir, FnDeclFlags}; | |
| 52 | use rustc_middle::span_bug; | |
| 53 | use rustc_middle::ty::{Asyncness, PerOwnerResolverData}; | |
| 54 | use rustc_span::def_id::{DefId, LocalDefId}; | |
| 55 | use rustc_span::symbol::kw; | |
| 56 | use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; | |
| 57 | ||
| 58 | use crate::delegation::generics::{ | |
| 59 | GenericsGenerationResult, GenericsGenerationResults, GenericsPosition, | |
| 60 | }; | |
| 61 | use crate::diagnostics::{ | |
| 62 | CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion, | |
| 63 | DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee, | |
| 64 | }; | |
| 65 | use crate::{ | |
| 66 | AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, | |
| 67 | }; | |
| 68 | ||
| 69 | mod generics; | |
| 70 | ||
| 71 | pub(crate) struct DelegationResults<'hir> { | |
| 72 | pub body_id: hir::BodyId, | |
| 73 | pub sig: hir::FnSig<'hir>, | |
| 74 | pub ident: Ident, | |
| 75 | pub generics: &'hir hir::Generics<'hir>, | |
| 76 | } | |
| 77 | ||
| 78 | struct AttrAdditionInfo { | |
| 79 | pub equals: fn(&hir::Attribute) -> bool, | |
| 80 | pub kind: AttrAdditionKind, | |
| 81 | } | |
| 82 | ||
| 83 | enum AttrAdditionKind { | |
| 84 | Default { factory: fn(Span) -> hir::Attribute }, | |
| 85 | Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute }, | |
| 86 | } | |
| 87 | ||
| 88 | /// Summary info about function parameters. | |
| 89 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | |
| 90 | struct ParamInfo { | |
| 91 | /// The number of function parameters, including any C variadic `...` parameter. | |
| 92 | pub param_count: usize, | |
| 93 | ||
| 94 | /// Whether the function arguments end in a C variadic `...` parameter. | |
| 95 | pub c_variadic: bool, | |
| 96 | ||
| 97 | /// The index of the splatted parameter, if any. | |
| 98 | pub splatted: Option<u8>, | |
| 99 | } | |
| 100 | ||
| 101 | const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; | |
| 102 | ||
| 103 | static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[ | |
| 104 | AttrAdditionInfo { | |
| 105 | equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })), | |
| 106 | kind: AttrAdditionKind::Inherit { | |
| 107 | factory: |span, original_attr| { | |
| 108 | let reason = match original_attr { | |
| 109 | hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason, | |
| 110 | _ => None, | |
| 111 | }; | |
| 112 | ||
| 113 | hir::Attribute::Parsed(AttributeKind::MustUse { span, reason }) | |
| 114 | }, | |
| 115 | }, | |
| 116 | }, | |
| 117 | AttrAdditionInfo { | |
| 118 | equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))), | |
| 119 | kind: AttrAdditionKind::Default { | |
| 120 | factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)), | |
| 121 | }, | |
| 122 | }, | |
| 123 | ]; | |
| 124 | ||
| 125 | impl<'hir> LoweringContext<'_, 'hir> { | |
| 126 | fn is_method(&self, def_id: DefId, span: Span) -> bool { | |
| 127 | match self.tcx.def_kind(def_id) { | |
| 128 | DefKind::Fn => false, | |
| 129 | DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(), | |
| 130 | _ => span_bug!(span, "unexpected DefKind for delegation item"), | |
| 131 | } | |
| 132 | } | |
| 133 | ||
| 134 | fn check_for_cycles(&self, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> { | |
| 135 | let mut visited: FxHashSet<DefId> = Default::default(); | |
| 136 | ||
| 137 | loop { | |
| 138 | visited.insert(def_id); | |
| 139 | ||
| 140 | // If def_id is in local crate and it corresponds to another delegation | |
| 141 | // it means that we refer to another delegation as a callee, so in order to obtain | |
| 142 | // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it. | |
| 143 | if let Some(local_id) = def_id.as_local() | |
| 144 | && let Some(info) = self.tcx.resolutions(()).delegation_infos.get(&local_id) | |
| 145 | && let Ok(id) = info.resolution_id | |
| 146 | { | |
| 147 | def_id = id; | |
| 148 | if visited.contains(&def_id) { | |
| 149 | return Err(match visited.len() { | |
| 150 | 1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }), | |
| 151 | _ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }), | |
| 152 | }); | |
| 153 | } | |
| 154 | } else { | |
| 155 | return Ok(()); | |
| 156 | } | |
| 157 | } | |
| 158 | } | |
| 159 | ||
| 160 | pub(crate) fn lower_delegation( | |
| 161 | &mut self, | |
| 162 | delegation: &Delegation, | |
| 163 | item_id: NodeId, | |
| 164 | ) -> DelegationResults<'hir> { | |
| 165 | let span = self.lower_span(delegation.last_segment_span()); | |
| 166 | ||
| 167 | let Some(info) = self.tcx.resolutions(()).delegation_infos.get(&self.owner.def_id) else { | |
| 168 | self.dcx().span_delayed_bug( | |
| 169 | span, | |
| 170 | format!("delegation resolution record was not found for {:?}", self.owner.def_id), | |
| 171 | ); | |
| 172 | ||
| 173 | return self.generate_delegation_error(span, delegation); | |
| 174 | }; | |
| 175 | ||
| 176 | let sig_id = info.resolution_id.and_then(|id| self.check_for_cycles(id, span).map(|_| id)); | |
| 177 | ||
| 178 | // Delegation can be missing from the `delegations_resolutions` table | |
| 179 | // in illegal places such as function bodies in extern blocks (see #151356). | |
| 180 | let Ok(sig_id) = sig_id else { | |
| 181 | self.dcx().span_delayed_bug( | |
| 182 | span, | |
| 183 | format!("LoweringContext: the delegation {:?} is unresolved", item_id), | |
| 184 | ); | |
| 185 | ||
| 186 | return self.generate_delegation_error(span, delegation); | |
| 187 | }; | |
| 188 | ||
| 189 | self.add_attrs_if_needed(span, sig_id); | |
| 190 | ||
| 191 | let is_method = self.is_method(sig_id, span); | |
| 192 | ||
| 193 | let param_info = self.param_info(sig_id); | |
| 194 | ||
| 195 | if !self.check_block_soundness(delegation, sig_id, is_method, param_info.param_count) { | |
| 196 | return self.generate_delegation_error(span, delegation); | |
| 197 | } | |
| 198 | ||
| 199 | let mut generics = self.uplift_delegation_generics(delegation, sig_id); | |
| 200 | ||
| 201 | let (body_id, call_expr_id, unused_target_expr) = self.lower_delegation_body( | |
| 202 | delegation, | |
| 203 | sig_id, | |
| 204 | param_info.param_count, | |
| 205 | &mut generics, | |
| 206 | span, | |
| 207 | ); | |
| 208 | ||
| 209 | let decl = self.lower_delegation_decl( | |
| 210 | delegation.source, | |
| 211 | sig_id, | |
| 212 | param_info, | |
| 213 | span, | |
| 214 | &generics, | |
| 215 | delegation.id, | |
| 216 | call_expr_id, | |
| 217 | unused_target_expr, | |
| 218 | ); | |
| 219 | ||
| 220 | let sig = self.lower_delegation_sig(sig_id, decl, span); | |
| 221 | let ident = self.lower_ident(delegation.ident); | |
| 222 | ||
| 223 | let generics = self.arena.alloc(hir::Generics { | |
| 224 | has_where_clause_predicates: false, | |
| 225 | params: self.arena.alloc_from_iter(generics.all_params()), | |
| 226 | predicates: self.arena.alloc_from_iter(generics.all_predicates()), | |
| 227 | span, | |
| 228 | where_clause_span: span, | |
| 229 | }); | |
| 230 | ||
| 231 | DelegationResults { body_id, sig, ident, generics } | |
| 232 | } | |
| 233 | ||
| 234 | fn check_block_soundness( | |
| 235 | &self, | |
| 236 | delegation: &Delegation, | |
| 237 | sig_id: DefId, | |
| 238 | is_method: bool, | |
| 239 | param_count: usize, | |
| 240 | ) -> bool { | |
| 241 | let Some(block) = delegation.body.as_ref() else { return true }; | |
| 242 | let should_generate_block = self.should_generate_block(delegation, sig_id, is_method); | |
| 243 | ||
| 244 | // Report an error if user has explicitly specified delegation's target expression | |
| 245 | // in a single delegation when reused function has no params. | |
| 246 | if param_count == 0 && should_generate_block { | |
| 247 | self.dcx().emit_err(DelegationBlockSpecifiedWhenNoParams { span: block.span }); | |
| 248 | return false; | |
| 249 | } | |
| 250 | ||
| 251 | struct DefinitionsFinder<'a> { | |
| 252 | all_owners: &'a NodeMap<PerOwnerResolverData<'a>>, | |
| 253 | // `self.owner.node_id_to_def_id` | |
| 254 | nested_def_ids: &'a NodeMap<LocalDefId>, | |
| 255 | } | |
| 256 | ||
| 257 | impl<'a> ast::visit::Visitor<'a> for DefinitionsFinder<'a> { | |
| 258 | type Result = ControlFlow<()>; | |
| 259 | ||
| 260 | fn visit_id(&mut self, id: NodeId) -> Self::Result { | |
| 261 | /* | |
| 262 | (from `tests\ui\delegation\target-expr-removal-defs-inside.rs`): | |
| 263 | ```rust | |
| 264 | reuse impl Trait for S1 { | |
| 265 | some::path::<{ fn foo() {} }>::xd(); | |
| 266 | fn foo() {} | |
| 267 | self.0 | |
| 268 | } | |
| 269 | ``` | |
| 270 | ||
| 271 | Constant from unresolved path will be in `nested_owners`, | |
| 272 | `fn foo() {}` will not be in `nested_owners` but will be in `owners`, | |
| 273 | both have `LocalDefId`, so we check those two maps. | |
| 274 | */ | |
| 275 | match self.all_owners.contains_key(&id) || self.nested_def_ids.contains_key(&id) { | |
| 276 | true => ControlFlow::Break(()), | |
| 277 | false => ControlFlow::Continue(()), | |
| 278 | } | |
| 279 | } | |
| 280 | } | |
| 281 | ||
| 282 | let mut collector = DefinitionsFinder { | |
| 283 | all_owners: &self.resolver.owners, | |
| 284 | nested_def_ids: &self.owner.node_id_to_def_id, | |
| 285 | }; | |
| 286 | ||
| 287 | let contains_defs = collector.visit_block(block).is_break(); | |
| 288 | ||
| 289 | // If there are definitions inside and we can't delete target expression, so report an error. | |
| 290 | // FIXME(fn_delegation): support deletion of target expression with defs inside. | |
| 291 | if !should_generate_block && contains_defs { | |
| 292 | self.dcx().emit_err(DelegationAttemptedBlockWithDefsDeletion { span: block.span }); | |
| 293 | return false; | |
| 294 | } | |
| 295 | ||
| 296 | true | |
| 297 | } | |
| 298 | ||
| 299 | fn should_generate_block( | |
| 300 | &self, | |
| 301 | delegation: &Delegation, | |
| 302 | sig_id: DefId, | |
| 303 | is_method: bool, | |
| 304 | ) -> bool { | |
| 305 | is_method | |
| 306 | || matches!(self.tcx.def_kind(sig_id), DefKind::Fn) | |
| 307 | || matches!(delegation.source, DelegationSource::Single) | |
| 308 | } | |
| 309 | ||
| 310 | fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) { | |
| 311 | let new_attrs = | |
| 312 | self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID)); | |
| 313 | ||
| 314 | if new_attrs.is_empty() { | |
| 315 | return; | |
| 316 | } | |
| 317 | ||
| 318 | let new_arena_allocated_attrs = match self.attrs.get(&PARENT_ID) { | |
| 319 | Some(existing_attrs) => self.arena.alloc_from_iter( | |
| 320 | existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()), | |
| 321 | ), | |
| 322 | None => self.arena.alloc_from_iter(new_attrs.into_iter()), | |
| 323 | }; | |
| 324 | ||
| 325 | self.attrs.insert(PARENT_ID, new_arena_allocated_attrs); | |
| 326 | } | |
| 327 | ||
| 328 | fn create_new_attrs( | |
| 329 | &self, | |
| 330 | candidate_additions: &[AttrAdditionInfo], | |
| 331 | span: Span, | |
| 332 | sig_id: DefId, | |
| 333 | existing_attrs: Option<&&[hir::Attribute]>, | |
| 334 | ) -> Vec<hir::Attribute> { | |
| 335 | candidate_additions | |
| 336 | .iter() | |
| 337 | .filter_map(|addition_info| { | |
| 338 | if let Some(existing_attrs) = existing_attrs | |
| 339 | && existing_attrs | |
| 340 | .iter() | |
| 341 | .any(|existing_attr| (addition_info.equals)(existing_attr)) | |
| 342 | { | |
| 343 | return None; | |
| 344 | } | |
| 345 | ||
| 346 | match addition_info.kind { | |
| 347 | AttrAdditionKind::Default { factory } => Some(factory(span)), | |
| 348 | AttrAdditionKind::Inherit { factory, .. } => | |
| 349 | { | |
| 350 | #[allow(deprecated)] | |
| 351 | self.tcx | |
| 352 | .get_all_attrs(sig_id) | |
| 353 | .iter() | |
| 354 | .find_map(|a| (addition_info.equals)(a).then(|| factory(span, a))) | |
| 355 | } | |
| 356 | } | |
| 357 | }) | |
| 358 | .collect::<Vec<_>>() | |
| 359 | } | |
| 360 | ||
| 361 | fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> { | |
| 362 | self.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()) | |
| 363 | } | |
| 364 | ||
| 365 | /// Returns function parameter info, including C variadic `...` and `#[splat]` if present. | |
| 366 | fn param_info(&self, def_id: DefId) -> ParamInfo { | |
| 367 | let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder(); | |
| 368 | ||
| 369 | ParamInfo { | |
| 370 | param_count: sig.inputs().len() + usize::from(sig.c_variadic()), | |
| 371 | c_variadic: sig.c_variadic(), | |
| 372 | splatted: sig.splatted(), | |
| 373 | } | |
| 374 | } | |
| 375 | ||
| 376 | fn lower_delegation_decl( | |
| 377 | &mut self, | |
| 378 | source: DelegationSource, | |
| 379 | sig_id: DefId, | |
| 380 | param_info: ParamInfo, | |
| 381 | span: Span, | |
| 382 | generics: &GenericsGenerationResults<'hir>, | |
| 383 | call_path_node_id: NodeId, | |
| 384 | call_expr_id: HirId, | |
| 385 | unused_target_expr: bool, | |
| 386 | ) -> &'hir hir::FnDecl<'hir> { | |
| 387 | let ParamInfo { param_count, c_variadic, splatted } = param_info; | |
| 388 | ||
| 389 | // The last parameter in C variadic functions is skipped in the signature, | |
| 390 | // like during regular lowering. | |
| 391 | let decl_param_count = param_count - c_variadic as usize; | |
| 392 | let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty { | |
| 393 | hir_id: self.next_id(), | |
| 394 | kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( | |
| 395 | sig_id, | |
| 396 | hir::InferDelegationSig::Input(arg), | |
| 397 | )), | |
| 398 | span, | |
| 399 | })); | |
| 400 | ||
| 401 | let output = self.arena.alloc(hir::Ty { | |
| 402 | hir_id: self.next_id(), | |
| 403 | kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( | |
| 404 | sig_id, | |
| 405 | hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationInfo { | |
| 406 | call_expr_id, | |
| 407 | call_path_res: self.get_resolution_id(call_path_node_id), | |
| 408 | child_seg_id: generics.child.args_segment_id, | |
| 409 | child_seg_id_for_sig: generics.child.segment_id_for_sig(), | |
| 410 | parent_seg_id_for_sig: generics.parent.segment_id_for_sig(), | |
| 411 | self_ty_propagation_kind: generics.self_ty_propagation_kind, | |
| 412 | group_id: { | |
| 413 | let id = match source { | |
| 414 | DelegationSource::Single => None, | |
| 415 | DelegationSource::List(expn_id) => Some(expn_id), | |
| 416 | DelegationSource::Glob => { | |
| 417 | Some(self.tcx.expn_that_defined(self.owner.def_id).expect_local()) | |
| 418 | } | |
| 419 | }; | |
| 420 | ||
| 421 | id.map(|id| (id, unused_target_expr)) | |
| 422 | }, | |
| 423 | })), | |
| 424 | )), | |
| 425 | span, | |
| 426 | }); | |
| 427 | ||
| 428 | self.arena.alloc(hir::FnDecl { | |
| 429 | inputs, | |
| 430 | output: hir::FnRetTy::Return(output), | |
| 431 | fn_decl_kind: FnDeclFlags::default() | |
| 432 | .set_lifetime_elision_allowed(true) | |
| 433 | .set_c_variadic(c_variadic) | |
| 434 | .set_splatted(splatted, inputs.len()) | |
| 435 | .unwrap(), | |
| 436 | }) | |
| 437 | } | |
| 438 | ||
| 439 | fn lower_delegation_sig( | |
| 440 | &mut self, | |
| 441 | sig_id: DefId, | |
| 442 | decl: &'hir hir::FnDecl<'hir>, | |
| 443 | span: Span, | |
| 444 | ) -> hir::FnSig<'hir> { | |
| 445 | let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); | |
| 446 | let asyncness = match self.tcx.asyncness(sig_id) { | |
| 447 | Asyncness::Yes => hir::IsAsync::Async(span), | |
| 448 | Asyncness::No => hir::IsAsync::NotAsync, | |
| 449 | }; | |
| 450 | ||
| 451 | let header = hir::FnHeader { | |
| 452 | safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features { | |
| 453 | hir::HeaderSafety::SafeTargetFeatures | |
| 454 | } else { | |
| 455 | hir::HeaderSafety::Normal(sig.safety()) | |
| 456 | }, | |
| 457 | constness: self.tcx.constness(sig_id), | |
| 458 | asyncness, | |
| 459 | abi: sig.abi(), | |
| 460 | }; | |
| 461 | ||
| 462 | hir::FnSig { decl, header, span } | |
| 463 | } | |
| 464 | ||
| 465 | fn generate_param( | |
| 466 | &mut self, | |
| 467 | is_method: bool, | |
| 468 | idx: usize, | |
| 469 | span: Span, | |
| 470 | ) -> (hir::Param<'hir>, NodeId) { | |
| 471 | let pat_node_id = self.next_node_id(); | |
| 472 | let pat_id = self.lower_node_id(pat_node_id); | |
| 473 | // FIXME(cjgillot) AssocItem currently relies on self parameter being exactly named `self`. | |
| 474 | let name = if is_method && idx == 0 { | |
| 475 | kw::SelfLower | |
| 476 | } else { | |
| 477 | Symbol::intern(&format!("arg{idx}")) | |
| 478 | }; | |
| 479 | let ident = Ident::with_dummy_span(name); | |
| 480 | let pat = self.arena.alloc(hir::Pat { | |
| 481 | hir_id: pat_id, | |
| 482 | kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None), | |
| 483 | span, | |
| 484 | default_binding_modes: false, | |
| 485 | }); | |
| 486 | ||
| 487 | (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id) | |
| 488 | } | |
| 489 | ||
| 490 | fn generate_arg( | |
| 491 | &mut self, | |
| 492 | is_method: bool, | |
| 493 | idx: usize, | |
| 494 | param_id: HirId, | |
| 495 | span: Span, | |
| 496 | ) -> hir::Expr<'hir> { | |
| 497 | // FIXME(cjgillot) AssocItem currently relies on self parameter being exactly named `self`. | |
| 498 | let name = if is_method && idx == 0 { | |
| 499 | kw::SelfLower | |
| 500 | } else { | |
| 501 | Symbol::intern(&format!("arg{idx}")) | |
| 502 | }; | |
| 503 | ||
| 504 | let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment { | |
| 505 | ident: Ident::with_dummy_span(name), | |
| 506 | hir_id: self.next_id(), | |
| 507 | res: Res::Local(param_id), | |
| 508 | args: None, | |
| 509 | infer_args: false, | |
| 510 | delegation_child_segment: false, | |
| 511 | })); | |
| 512 | ||
| 513 | let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); | |
| 514 | self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span) | |
| 515 | } | |
| 516 | ||
| 517 | fn lower_delegation_body( | |
| 518 | &mut self, | |
| 519 | delegation: &Delegation, | |
| 520 | sig_id: DefId, | |
| 521 | param_count: usize, | |
| 522 | generics: &mut GenericsGenerationResults<'hir>, | |
| 523 | span: Span, | |
| 524 | ) -> (BodyId, HirId, bool) { | |
| 525 | let block = delegation.body.as_deref(); | |
| 526 | let mut call_expr_id = HirId::INVALID; | |
| 527 | let mut unused_target_expr = false; | |
| 528 | ||
| 529 | let block_id = self.lower_body(|this| { | |
| 530 | let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count); | |
| 531 | let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count); | |
| 532 | let mut stmts: &[hir::Stmt<'hir>] = &[]; | |
| 533 | ||
| 534 | let is_method = this.is_method(sig_id, span); | |
| 535 | let should_generate_block = this.should_generate_block(delegation, sig_id, is_method); | |
| 536 | ||
| 537 | // Consider non-specified target expression as generated, | |
| 538 | // as we do not want to emit error when target expression is | |
| 539 | // not specified. | |
| 540 | unused_target_expr = block.is_some() && (param_count == 0 || !should_generate_block); | |
| 541 | ||
| 542 | for idx in 0..param_count { | |
| 543 | let (param, pat_node_id) = this.generate_param(is_method, idx, span); | |
| 544 | parameters.push(param); | |
| 545 | ||
| 546 | let generate_arg = | |
| 547 | |this: &mut Self| this.generate_arg(is_method, idx, param.pat.hir_id, span); | |
| 548 | ||
| 549 | let arg = if let Some(block) = block | |
| 550 | && idx == 0 | |
| 551 | && should_generate_block | |
| 552 | { | |
| 553 | let mut self_resolver = SelfResolver { | |
| 554 | ctxt: this, | |
| 555 | path_id: delegation.id, | |
| 556 | self_param_id: pat_node_id, | |
| 557 | }; | |
| 558 | self_resolver.visit_block(block); | |
| 559 | // Target expr needs to lower `self` path. | |
| 560 | this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); | |
| 561 | ||
| 562 | // Lower with `HirId::INVALID` as we will use only expr and stmts. | |
| 563 | // FIXME(fn_delegation): Alternatives for target expression lowering: | |
| 564 | // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600. | |
| 565 | let block = this.lower_block_noalloc(HirId::INVALID, block, false); | |
| 566 | ||
| 567 | stmts = block.stmts; | |
| 568 | ||
| 569 | // The behavior of the delegation's target expression differs from the | |
| 570 | // behavior of the usual block, where if there is no final expression | |
| 571 | // the `()` is returned. In case of the similar situation in delegation | |
| 572 | // (no final expression) we propagate first argument instead of replacing | |
| 573 | // it with `()`. | |
| 574 | if let Some(&expr) = block.expr { expr } else { generate_arg(this) } | |
| 575 | } else { | |
| 576 | generate_arg(this) | |
| 577 | }; | |
| 578 | ||
| 579 | args.push(arg); | |
| 580 | } | |
| 581 | ||
| 582 | let (final_expr, hir_id) = | |
| 583 | this.finalize_body_lowering(delegation, stmts, args, generics, span); | |
| 584 | ||
| 585 | call_expr_id = hir_id; | |
| 586 | ||
| 587 | (this.arena.alloc_from_iter(parameters), final_expr) | |
| 588 | }); | |
| 589 | ||
| 590 | debug_assert_ne!(call_expr_id, HirId::INVALID); | |
| 591 | ||
| 592 | (block_id, call_expr_id, unused_target_expr) | |
| 593 | } | |
| 594 | ||
| 595 | fn finalize_body_lowering( | |
| 596 | &mut self, | |
| 597 | delegation: &Delegation, | |
| 598 | stmts: &'hir [hir::Stmt<'hir>], | |
| 599 | args: Vec<hir::Expr<'hir>>, | |
| 600 | generics: &mut GenericsGenerationResults<'hir>, | |
| 601 | span: Span, | |
| 602 | ) -> (hir::Expr<'hir>, HirId) { | |
| 603 | let path = self.lower_qpath( | |
| 604 | delegation.id, | |
| 605 | &delegation.qself, | |
| 606 | &delegation.path, | |
| 607 | ParamMode::Optional, | |
| 608 | AllowReturnTypeNotation::No, | |
| 609 | ImplTraitContext::Disallowed(ImplTraitPosition::Path), | |
| 610 | None, | |
| 611 | ); | |
| 612 | ||
| 613 | let new_path = match path { | |
| 614 | hir::QPath::Resolved(ty, path) => { | |
| 615 | let mut new_path = path.clone(); | |
| 616 | let len = new_path.segments.len(); | |
| 617 | ||
| 618 | new_path.segments = self.arena.alloc_from_iter( | |
| 619 | new_path.segments.iter().enumerate().map(|(idx, segment)| { | |
| 620 | if idx + 2 == len { | |
| 621 | self.process_segment(span, segment, &mut generics.parent) | |
| 622 | } else if idx + 1 == len { | |
| 623 | self.process_segment(span, segment, &mut generics.child) | |
| 624 | } else { | |
| 625 | segment.clone() | |
| 626 | } | |
| 627 | }), | |
| 628 | ); | |
| 629 | ||
| 630 | // Explicitly create `Self` self-type in case of infers or static | |
| 631 | // free-to-trait reuses. | |
| 632 | let ty = match generics.self_ty_propagation_kind { | |
| 633 | Some(hir::DelegationSelfTyPropagationKind::SelfParam) => { | |
| 634 | let self_param = generics.parent.generics.find_self_param(); | |
| 635 | let path = self.create_generic_arg_path(self_param); | |
| 636 | let kind = hir::TyKind::Path(path); | |
| 637 | ||
| 638 | let ty = match ty { | |
| 639 | Some(ty) => hir::Ty { kind, ..ty.clone() }, | |
| 640 | None => hir::Ty { kind, hir_id: self.next_id(), span }, | |
| 641 | }; | |
| 642 | ||
| 643 | Some(&*self.arena.alloc(ty)) | |
| 644 | } | |
| 645 | _ => ty, | |
| 646 | }; | |
| 647 | ||
| 648 | hir::QPath::Resolved(ty, self.arena.alloc(new_path)) | |
| 649 | } | |
| 650 | hir::QPath::TypeRelative(..) => unreachable!("until inherent methods are supported"), | |
| 651 | }; | |
| 652 | ||
| 653 | if let Some(hir::DelegationSelfTyPropagationKind::SelfTy(id)) = | |
| 654 | generics.self_ty_propagation_kind.as_mut() | |
| 655 | { | |
| 656 | *id = match new_path { | |
| 657 | hir::QPath::Resolved(ty, _) => { | |
| 658 | ty.expect("must contain self type as `SelfTy` propagation kind is specified") | |
| 659 | } | |
| 660 | hir::QPath::TypeRelative(ty, _) => ty, | |
| 661 | } | |
| 662 | .hir_id; | |
| 663 | } | |
| 664 | ||
| 665 | let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span)); | |
| 666 | let args = self.arena.alloc_from_iter(args); | |
| 667 | let call = self.mk_expr(hir::ExprKind::Call(callee_path, args), span); | |
| 668 | ||
| 669 | let expr = if let Some((parent, of_trait)) = self.should_wrap_return_value(delegation) { | |
| 670 | let res = Res::SelfTyAlias { alias_to: parent.to_def_id(), is_trait_impl: of_trait }; | |
| 671 | let ident = Ident::new(kw::SelfUpper, span); | |
| 672 | let path = self.create_resolved_path(res, ident, span); | |
| 673 | ||
| 674 | // FIXME(fn_delegation): add default `..` for all other fields. | |
| 675 | let initializer = hir::ExprKind::Struct( | |
| 676 | self.arena.alloc(path), | |
| 677 | self.arena.alloc_slice(&[hir::ExprField { | |
| 678 | hir_id: self.next_id(), | |
| 679 | is_shorthand: false, | |
| 680 | ident: Ident::new(sym::integer(0), span), | |
| 681 | expr: self.arena.alloc(call), | |
| 682 | span, | |
| 683 | }]), | |
| 684 | hir::StructTailExpr::None, | |
| 685 | ); | |
| 686 | ||
| 687 | self.arena.alloc(self.mk_expr(initializer, span)) | |
| 688 | } else { | |
| 689 | self.arena.alloc(call) | |
| 690 | }; | |
| 691 | ||
| 692 | let block = self.arena.alloc(hir::Block { | |
| 693 | stmts, | |
| 694 | expr: Some(expr), | |
| 695 | hir_id: self.next_id(), | |
| 696 | rules: hir::BlockCheckMode::DefaultBlock, | |
| 697 | span, | |
| 698 | targeted_by_break: false, | |
| 699 | }); | |
| 700 | ||
| 701 | (self.mk_expr(hir::ExprKind::Block(block, None), span), call.hir_id) | |
| 702 | } | |
| 703 | ||
| 704 | fn should_wrap_return_value(&self, delegation: &Delegation) -> Option<(LocalDefId, bool)> { | |
| 705 | // Heuristic: don't do wrapping if there is no target expression. | |
| 706 | if delegation.body.is_none() { | |
| 707 | return None; | |
| 708 | } | |
| 709 | ||
| 710 | let tcx = self.tcx; | |
| 711 | let parent = tcx.local_parent(self.owner.def_id); | |
| 712 | let parent_kind = tcx.def_kind(parent); | |
| 713 | ||
| 714 | // Apply wrapping for delegations inside | |
| 715 | // 1) Trait impls, as the return type of both signature function | |
| 716 | // and generated delegation has `Self` generic param returned | |
| 717 | // (checked below). | |
| 718 | // FIXME(fn_delegation): think of enabling wrapping in more scenarios: | |
| 719 | // trait-(impl)-to-free | |
| 720 | // trait-(impl)-to-inherent | |
| 721 | // inherent-to-free | |
| 722 | // 2) Inherent methods when delegating to trait, as we change the type of | |
| 723 | // `Self` to type of struct or enum we delegate from. | |
| 724 | if !matches!(tcx.def_kind(parent), DefKind::Impl { .. }) { | |
| 725 | return None; | |
| 726 | } | |
| 727 | ||
| 728 | let is_trait_impl = parent_kind == DefKind::Impl { of_trait: true }; | |
| 729 | ||
| 730 | // Check that delegation path resolves to a trait AssocFn, not to a free method. | |
| 731 | Some((parent, is_trait_impl)).filter(|_| { | |
| 732 | self.get_resolution_id(delegation.id).is_some_and(|id| { | |
| 733 | tcx.def_kind(id) == DefKind::AssocFn | |
| 734 | // Check that the return type of the callee is `Self` param. | |
| 735 | // After previous check we are sure that `sig_id` and `delegation.id` | |
| 736 | // point to the same function. | |
| 737 | && tcx.def_kind(tcx.parent(id)) == DefKind::Trait | |
| 738 | && tcx.fn_sig(id).skip_binder().output().skip_binder().is_param(0) | |
| 739 | }) | |
| 740 | }) | |
| 741 | } | |
| 742 | ||
| 743 | fn process_segment( | |
| 744 | &mut self, | |
| 745 | span: Span, | |
| 746 | segment: &hir::PathSegment<'hir>, | |
| 747 | result: &mut GenericsGenerationResult<'hir>, | |
| 748 | ) -> hir::PathSegment<'hir> { | |
| 749 | let infer_indices = result.generics.infer_indices(); | |
| 750 | result.generics.into_hir_generics(self, span); | |
| 751 | ||
| 752 | let mut segment = segment.clone(); | |
| 753 | let mut args_iter = result.generics.create_args_iterator(); | |
| 754 | ||
| 755 | let new_args = segment | |
| 756 | .args | |
| 757 | .filter(|args| !args.is_empty()) | |
| 758 | .map(|args| { | |
| 759 | self.arena.alloc_from_iter(args.args.iter().enumerate().map(|(idx, arg)| { | |
| 760 | if infer_indices.contains(&idx) { | |
| 761 | args_iter.next(self, |_| arg.hir_id()).expect("arg must exist for infer") | |
| 762 | } else { | |
| 763 | *arg | |
| 764 | } | |
| 765 | })) | |
| 766 | }) | |
| 767 | .unwrap_or_else(|| self.arena.alloc_from_iter(args_iter.consume_all(self))); | |
| 768 | ||
| 769 | // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). | |
| 770 | segment.args = (!new_args.is_empty()).then(|| { | |
| 771 | &*self.arena.alloc(hir::GenericArgs { | |
| 772 | args: new_args, | |
| 773 | constraints: &[], | |
| 774 | parenthesized: hir::GenericArgsParentheses::No, | |
| 775 | span_ext: segment.args.map_or(span, |args| args.span_ext), | |
| 776 | }) | |
| 777 | }); | |
| 778 | ||
| 779 | result.args_segment_id = segment.hir_id; | |
| 780 | result.use_for_sig_inheritance = !result.generics.is_trait_impl(); | |
| 781 | ||
| 782 | segment.delegation_child_segment = result.generics.pos() == GenericsPosition::Child; | |
| 783 | ||
| 784 | segment | |
| 785 | } | |
| 786 | ||
| 787 | fn generate_delegation_error( | |
| 788 | &mut self, | |
| 789 | span: Span, | |
| 790 | delegation: &Delegation, | |
| 791 | ) -> DelegationResults<'hir> { | |
| 792 | let decl = self.arena.alloc(hir::FnDecl::dummy(span)); | |
| 793 | ||
| 794 | let header = self.generate_header_error(); | |
| 795 | let sig = hir::FnSig { decl, header, span }; | |
| 796 | ||
| 797 | let ident = self.lower_ident(delegation.ident); | |
| 798 | ||
| 799 | let body_id = self.lower_body(|this| { | |
| 800 | let path = this.lower_qpath( | |
| 801 | delegation.id, | |
| 802 | &delegation.qself, | |
| 803 | &delegation.path, | |
| 804 | ParamMode::Optional, | |
| 805 | AllowReturnTypeNotation::No, | |
| 806 | ImplTraitContext::Disallowed(ImplTraitPosition::Path), | |
| 807 | None, | |
| 808 | ); | |
| 809 | ||
| 810 | let callee_path = this.arena.alloc(this.mk_expr(hir::ExprKind::Path(path), span)); | |
| 811 | let args = if let Some(block) = delegation.body.as_ref() { | |
| 812 | this.arena.alloc_slice(&[this.lower_block_expr(block)]) | |
| 813 | } else { | |
| 814 | &mut [] | |
| 815 | }; | |
| 816 | ||
| 817 | let call = this.arena.alloc(this.mk_expr(hir::ExprKind::Call(callee_path, args), span)); | |
| 818 | ||
| 819 | let block = this.arena.alloc(hir::Block { | |
| 820 | stmts: &[], | |
| 821 | expr: Some(call), | |
| 822 | hir_id: this.next_id(), | |
| 823 | rules: hir::BlockCheckMode::DefaultBlock, | |
| 824 | span, | |
| 825 | targeted_by_break: false, | |
| 826 | }); | |
| 827 | ||
| 828 | (&[], this.mk_expr(hir::ExprKind::Block(block, None), span)) | |
| 829 | }); | |
| 830 | ||
| 831 | let generics = hir::Generics::empty(); | |
| 832 | DelegationResults { ident, generics, body_id, sig } | |
| 833 | } | |
| 834 | ||
| 835 | fn generate_header_error(&self) -> hir::FnHeader { | |
| 836 | hir::FnHeader { | |
| 837 | safety: hir::Safety::Safe.into(), | |
| 838 | constness: hir::Constness::NotConst, | |
| 839 | asyncness: hir::IsAsync::NotAsync, | |
| 840 | abi: ExternAbi::Rust, | |
| 841 | } | |
| 842 | } | |
| 843 | ||
| 844 | #[inline] | |
| 845 | fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> { | |
| 846 | hir::Expr { hir_id: self.next_id(), kind, span } | |
| 847 | } | |
| 848 | } | |
| 849 | ||
| 850 | struct SelfResolver<'a, 'b, 'hir> { | |
| 851 | ctxt: &'a mut LoweringContext<'b, 'hir>, | |
| 852 | path_id: NodeId, | |
| 853 | self_param_id: NodeId, | |
| 854 | } | |
| 855 | ||
| 856 | impl SelfResolver<'_, '_, '_> { | |
| 857 | fn try_replace_id(&mut self, id: NodeId) { | |
| 858 | if let Some(res) = self.ctxt.get_partial_res(id) | |
| 859 | && let Some(Res::Local(sig_id)) = res.full_res() | |
| 860 | && sig_id == self.path_id | |
| 861 | { | |
| 862 | self.ctxt.partial_res_overrides.insert(id, self.self_param_id); | |
| 863 | } | |
| 864 | } | |
| 865 | } | |
| 866 | ||
| 867 | impl<'ast> Visitor<'ast> for SelfResolver<'_, '_, '_> { | |
| 868 | fn visit_id(&mut self, id: NodeId) { | |
| 869 | self.try_replace_id(id); | |
| 870 | } | |
| 871 | } |
compiler/rustc_ast_lowering/src/delegation/attributes.rs created+86| ... | ... | @@ -0,0 +1,86 @@ |
| 1 | use rustc_hir::attrs::{AttributeKind, InlineAttr}; | |
| 2 | use rustc_hir::{self as hir}; | |
| 3 | use rustc_span::Span; | |
| 4 | use rustc_span::def_id::DefId; | |
| 5 | ||
| 6 | use crate::LoweringContext; | |
| 7 | use crate::delegation::DelegationResolution; | |
| 8 | ||
| 9 | struct AdditionInfo { | |
| 10 | pub equals: fn(&hir::Attribute) -> bool, | |
| 11 | pub kind: AdditionKind, | |
| 12 | } | |
| 13 | ||
| 14 | enum AdditionKind { | |
| 15 | Default { factory: fn(Span) -> hir::Attribute }, | |
| 16 | Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute }, | |
| 17 | } | |
| 18 | ||
| 19 | static ADDITIONS: &[AdditionInfo] = &[ | |
| 20 | AdditionInfo { | |
| 21 | equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::MustUse { .. })), | |
| 22 | kind: AdditionKind::Inherit { | |
| 23 | factory: |span, original_attr| { | |
| 24 | let reason = match original_attr { | |
| 25 | hir::Attribute::Parsed(AttributeKind::MustUse { reason, .. }) => *reason, | |
| 26 | _ => None, | |
| 27 | }; | |
| 28 | ||
| 29 | hir::Attribute::Parsed(AttributeKind::MustUse { span, reason }) | |
| 30 | }, | |
| 31 | }, | |
| 32 | }, | |
| 33 | AdditionInfo { | |
| 34 | equals: |a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..))), | |
| 35 | kind: AdditionKind::Default { | |
| 36 | factory: |span| hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span)), | |
| 37 | }, | |
| 38 | }, | |
| 39 | ]; | |
| 40 | ||
| 41 | impl<'hir> LoweringContext<'_, 'hir> { | |
| 42 | pub(super) fn add_attrs_if_needed(&mut self, resolution: &DelegationResolution) { | |
| 43 | let &DelegationResolution { span, sig_id, .. } = resolution; | |
| 44 | ||
| 45 | const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; | |
| 46 | let new_attrs = self.create_new_attrs(span, sig_id, self.attrs.get(&PARENT_ID)); | |
| 47 | ||
| 48 | if !new_attrs.is_empty() { | |
| 49 | let new_attrs = match self.attrs.get(&PARENT_ID) { | |
| 50 | Some(existing_attrs) => self.arena.alloc_from_iter( | |
| 51 | existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()), | |
| 52 | ), | |
| 53 | None => self.arena.alloc_from_iter(new_attrs.into_iter()), | |
| 54 | }; | |
| 55 | ||
| 56 | self.attrs.insert(PARENT_ID, new_attrs); | |
| 57 | } | |
| 58 | } | |
| 59 | ||
| 60 | fn create_new_attrs( | |
| 61 | &self, | |
| 62 | span: Span, | |
| 63 | sig_id: DefId, | |
| 64 | existing: Option<&&[hir::Attribute]>, | |
| 65 | ) -> Vec<hir::Attribute> { | |
| 66 | ADDITIONS | |
| 67 | .iter() | |
| 68 | .filter_map(|addition| { | |
| 69 | existing | |
| 70 | .is_none_or(|attrs| !attrs.iter().any(|a| (addition.equals)(a))) | |
| 71 | .then(|| match addition.kind { | |
| 72 | AdditionKind::Default { factory } => Some(factory(span)), | |
| 73 | AdditionKind::Inherit { factory, .. } => | |
| 74 | { | |
| 75 | #[allow(deprecated)] | |
| 76 | self.tcx | |
| 77 | .get_all_attrs(sig_id) | |
| 78 | .iter() | |
| 79 | .find_map(|a| (addition.equals)(a).then(|| factory(span, a))) | |
| 80 | } | |
| 81 | }) | |
| 82 | .flatten() | |
| 83 | }) | |
| 84 | .collect::<Vec<_>>() | |
| 85 | } | |
| 86 | } |
compiler/rustc_ast_lowering/src/delegation/generics.rs+186-111| ... | ... | @@ -4,12 +4,13 @@ use rustc_ast::*; |
| 4 | 4 | use rustc_data_structures::fx::FxHashSet; |
| 5 | 5 | use rustc_hir as hir; |
| 6 | 6 | use rustc_hir::def_id::DefId; |
| 7 | use rustc_middle::ty::GenericParamDefKind; | |
| 7 | use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; | |
| 8 | 8 | use rustc_middle::{bug, ty}; |
| 9 | 9 | use rustc_span::symbol::kw; |
| 10 | 10 | use rustc_span::{Ident, Span, sym}; |
| 11 | 11 | |
| 12 | 12 | use crate::LoweringContext; |
| 13 | use crate::delegation::resolution::resolver::DelegationResolver; | |
| 13 | 14 | use crate::diagnostics::DelegationInfersMismatch; |
| 14 | 15 | |
| 15 | 16 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] |
| ... | ... | @@ -237,74 +238,130 @@ impl<'hir> GenericsGenerationResult<'hir> { |
| 237 | 238 | } |
| 238 | 239 | } |
| 239 | 240 | |
| 240 | impl<'hir> GenericsGenerationResults<'hir> { | |
| 241 | pub(super) fn all_params(&self) -> impl Iterator<Item = hir::GenericParam<'hir>> { | |
| 242 | let parent = self.parent.generics.hir_generics_or_empty().params; | |
| 243 | let child = self.child.generics.hir_generics_or_empty().params; | |
| 241 | enum ParentSegmentArgs<'a> { | |
| 242 | /// Parent segment is valid and generic args are specified: | |
| 243 | /// `reuse Trait::<'static, ()>::foo;`. | |
| 244 | Specified(&'a AngleBracketedArgs), | |
| 245 | /// Parent segment is valid and args are not specified: | |
| 246 | /// `reuse Trait::foo;`. | |
| 247 | NotSpecified, | |
| 248 | /// Parent segment does not exist (`reuse foo`) or we can not | |
| 249 | /// add generics to it: | |
| 250 | /// ```rust | |
| 251 | /// mod to_reuse { | |
| 252 | /// fn foo() {} | |
| 253 | /// } | |
| 254 | /// | |
| 255 | /// // Can't add generic args to module. | |
| 256 | /// reuse to_reuse::foo; | |
| 257 | /// ``` | |
| 258 | Invalid, | |
| 259 | } | |
| 244 | 260 | |
| 245 | // Order generics, first we have parent and child lifetimes, | |
| 246 | // then parent and child types and consts. | |
| 247 | // `generics_of` in `rustc_hir_analysis` will order them anyway, | |
| 248 | // however we want the order to be consistent in HIR too. | |
| 249 | parent | |
| 250 | .iter() | |
| 251 | .filter(|p| p.is_lifetime()) | |
| 252 | .chain(child.iter().filter(|p| p.is_lifetime())) | |
| 253 | .chain(parent.iter().filter(|p| !p.is_lifetime())) | |
| 254 | .chain(child.iter().filter(|p| !p.is_lifetime())) | |
| 255 | .copied() | |
| 256 | } | |
| 261 | struct GenericsResolution<'a, 'tcx> { | |
| 262 | trait_impl: bool, | |
| 257 | 263 | |
| 258 | /// As we add hack predicates(`'a: 'a`) for all lifetimes (see `uplift_delegation_generic_params` | |
| 259 | /// and `generate_lifetime_predicate` functions) we need to add them to delegation generics. | |
| 260 | /// Those predicates will not affect resulting predicate inheritance and folding | |
| 261 | /// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature. | |
| 262 | pub(super) fn all_predicates(&self) -> impl Iterator<Item = hir::WherePredicate<'hir>> { | |
| 263 | self.parent | |
| 264 | .generics | |
| 265 | .hir_generics_or_empty() | |
| 266 | .predicates | |
| 267 | .into_iter() | |
| 268 | .chain(self.child.generics.hir_generics_or_empty().predicates) | |
| 269 | .copied() | |
| 270 | } | |
| 264 | parent_args: ParentSegmentArgs<'a>, | |
| 265 | child_args: Option<&'a AngleBracketedArgs>, | |
| 266 | ||
| 267 | sig_parent_params: &'tcx [ty::GenericParamDef], | |
| 268 | sig_child_params: &'tcx [ty::GenericParamDef], | |
| 269 | ||
| 270 | free_to_trait_delegation: bool, | |
| 271 | /// `reuse Trait::foo;`. | |
| 272 | qself_is_none: bool, | |
| 273 | /// `reuse <_ as Trait>::foo;`. | |
| 274 | qself_is_infer: bool, | |
| 275 | /// Whether we should generate `Self` generic param. | |
| 276 | generate_self: bool, | |
| 271 | 277 | } |
| 272 | 278 | |
| 273 | impl<'hir> LoweringContext<'_, 'hir> { | |
| 274 | pub(super) fn uplift_delegation_generics( | |
| 275 | &mut self, | |
| 276 | delegation: &Delegation, | |
| 279 | impl<'hir> DelegationResolver<'_, 'hir> { | |
| 280 | fn resolve_generics<'a>( | |
| 281 | &self, | |
| 282 | delegation: &'a Delegation, | |
| 277 | 283 | sig_id: DefId, |
| 278 | ) -> GenericsGenerationResults<'hir> { | |
| 279 | let delegation_parent_kind = self.tcx.def_kind(self.tcx.local_parent(self.owner.def_id)); | |
| 284 | ) -> GenericsResolution<'a, 'hir> { | |
| 285 | let tcx = self.tcx(); | |
| 286 | let delegation_parent_kind = tcx.def_kind(tcx.local_parent(self.owner_id())); | |
| 280 | 287 | |
| 281 | let segments = &delegation.path.segments; | |
| 282 | let len = segments.len(); | |
| 288 | let delegation_in_free_ctx = | |
| 289 | !matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. }); | |
| 283 | 290 | |
| 284 | let get_user_args = |idx: usize| -> Option<&AngleBracketedArgs> { | |
| 285 | let segment = &segments[idx]; | |
| 291 | let sig_parent = tcx.parent(sig_id); | |
| 292 | let sig_in_trait = matches!(tcx.def_kind(sig_parent), DefKind::Trait); | |
| 293 | let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait; | |
| 286 | 294 | |
| 287 | let Some(args) = segment.args.as_ref() else { return None }; | |
| 288 | let GenericArgs::AngleBracketed(args) = args else { | |
| 289 | self.tcx.dcx().span_delayed_bug( | |
| 290 | segment.span(), | |
| 291 | "expected angle-bracketed generic args in delegation segment", | |
| 292 | ); | |
| 295 | let mut sig_parent_params: &[ty::GenericParamDef] = &[]; | |
| 293 | 296 | |
| 294 | return None; | |
| 295 | }; | |
| 297 | let qself_is_infer = | |
| 298 | delegation.qself.as_ref().is_some_and(|qself| qself.ty.is_maybe_parenthesised_infer()); | |
| 296 | 299 | |
| 297 | // Treat empty args `reuse foo::<> as bar` as `reuse foo as bar`, | |
| 298 | // the same logic applied when we call function `fn f<T>(t: T)` | |
| 299 | // like that `f::<>(())`, in HIR no `<>` will be generated. | |
| 300 | (!args.args.is_empty()).then(|| args) | |
| 300 | let qself_is_none = delegation.qself.is_none(); | |
| 301 | ||
| 302 | let parent_args = if let [.., parent_segment, _] = &delegation.path.segments[..] { | |
| 303 | if let Some(res) = self.get_resolution_id(parent_segment.id) | |
| 304 | && matches!(tcx.def_kind(res), DefKind::Trait | DefKind::TraitAlias) | |
| 305 | { | |
| 306 | sig_parent_params = &tcx.generics_of(sig_parent).own_params; | |
| 307 | self.get_user_args(parent_segment) | |
| 308 | .map(|args| ParentSegmentArgs::Specified(args)) | |
| 309 | .unwrap_or(ParentSegmentArgs::NotSpecified) | |
| 310 | } else { | |
| 311 | ParentSegmentArgs::Invalid | |
| 312 | } | |
| 313 | } else { | |
| 314 | ParentSegmentArgs::Invalid | |
| 301 | 315 | }; |
| 302 | 316 | |
| 303 | let sig_params = &self.tcx.generics_of(sig_id).own_params[..]; | |
| 317 | GenericsResolution { | |
| 318 | parent_args, | |
| 319 | sig_parent_params, | |
| 320 | qself_is_none, | |
| 321 | qself_is_infer, | |
| 322 | free_to_trait_delegation, | |
| 323 | generate_self: free_to_trait_delegation && (qself_is_none || qself_is_infer), | |
| 324 | trait_impl: matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }), | |
| 325 | sig_child_params: &tcx.generics_of(sig_id).own_params, | |
| 326 | child_args: self.get_user_args( | |
| 327 | delegation.path.segments.last().expect("must be at least one segment"), | |
| 328 | ), | |
| 329 | } | |
| 330 | } | |
| 331 | ||
| 332 | fn get_user_args<'a>(&self, segment: &'a PathSegment) -> Option<&'a AngleBracketedArgs> { | |
| 333 | let Some(args) = &segment.args else { return None }; | |
| 334 | let GenericArgs::AngleBracketed(args) = args else { | |
| 335 | self.tcx().dcx().span_delayed_bug( | |
| 336 | segment.span(), | |
| 337 | "expected angle-bracketed generic args in delegation segment", | |
| 338 | ); | |
| 339 | ||
| 340 | return None; | |
| 341 | }; | |
| 342 | ||
| 343 | // Treat empty args `reuse foo::<> as bar` as `reuse foo as bar`, | |
| 344 | // the same logic applied when we call function `fn f<T>(t: T)` | |
| 345 | // like that `f::<>(())`, in HIR no `<>` will be generated. | |
| 346 | (!args.args.is_empty()).then(|| args) | |
| 347 | } | |
| 348 | ||
| 349 | pub(super) fn resolve_and_generate_generics( | |
| 350 | &self, | |
| 351 | delegation: &Delegation, | |
| 352 | sig_id: DefId, | |
| 353 | ) -> GenericsGenerationResults<'hir> { | |
| 354 | let res @ GenericsResolution { | |
| 355 | trait_impl, | |
| 356 | generate_self, | |
| 357 | sig_child_params, | |
| 358 | sig_parent_params, | |
| 359 | .. | |
| 360 | } = self.resolve_generics(delegation, sig_id); | |
| 304 | 361 | |
| 305 | 362 | // If we are in trait impl always generate function whose generics matches |
| 306 | 363 | // those that are defined in trait. |
| 307 | if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) { | |
| 364 | if trait_impl { | |
| 308 | 365 | // Considering parent generics, during signature inheritance |
| 309 | 366 | // we will take those args that are in trait impl header trait ref. |
| 310 | 367 | let parent = |
| ... | ... | @@ -312,78 +369,65 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 312 | 369 | |
| 313 | 370 | let parent = GenericsGenerationResult::new(parent); |
| 314 | 371 | |
| 315 | let child = DelegationGenerics::generate_all(sig_params, GenericsPosition::Child, true); | |
| 372 | let child = | |
| 373 | DelegationGenerics::generate_all(sig_child_params, GenericsPosition::Child, true); | |
| 374 | ||
| 316 | 375 | let child = GenericsGenerationResult::new(child); |
| 317 | 376 | |
| 318 | 377 | return GenericsGenerationResults { parent, child, self_ty_propagation_kind: None }; |
| 319 | 378 | } |
| 320 | 379 | |
| 321 | let delegation_in_free_ctx = | |
| 322 | !matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. }); | |
| 323 | ||
| 324 | let sig_parent = self.tcx.parent(sig_id); | |
| 325 | let sig_in_trait = matches!(self.tcx.def_kind(sig_parent), DefKind::Trait); | |
| 326 | let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait; | |
| 327 | ||
| 328 | let qself_is_infer = | |
| 329 | delegation.qself.as_ref().is_some_and(|qself| qself.ty.is_maybe_parenthesised_infer()); | |
| 330 | ||
| 331 | let qself_is_none = delegation.qself.is_none(); | |
| 332 | ||
| 333 | let generate_self = free_to_trait_delegation && (qself_is_none || qself_is_infer); | |
| 334 | ||
| 335 | let can_add_generics_to_parent = len >= 2 | |
| 336 | && self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| { | |
| 337 | matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias) | |
| 338 | }); | |
| 339 | ||
| 340 | let parent_generics = if can_add_generics_to_parent { | |
| 341 | let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params; | |
| 342 | ||
| 343 | if let Some(args) = get_user_args(len - 2) { | |
| 344 | DelegationGenerics { | |
| 345 | data: self.create_slots_from_args( | |
| 346 | args, | |
| 347 | &sig_parent_params[usize::from(!generate_self)..], | |
| 348 | generate_self, | |
| 349 | ), | |
| 350 | pos: GenericsPosition::Parent, | |
| 351 | trait_impl: false, | |
| 352 | } | |
| 353 | } else { | |
| 354 | DelegationGenerics::generate_all( | |
| 380 | let tcx = self.tcx(); | |
| 381 | let parent_generics = match res.parent_args { | |
| 382 | ParentSegmentArgs::Specified(args) => DelegationGenerics { | |
| 383 | data: Self::create_slots_from_args( | |
| 384 | tcx, | |
| 385 | args, | |
| 355 | 386 | &sig_parent_params[usize::from(!generate_self)..], |
| 356 | GenericsPosition::Parent, | |
| 357 | false, | |
| 358 | ) | |
| 387 | generate_self, | |
| 388 | ), | |
| 389 | pos: GenericsPosition::Parent, | |
| 390 | trait_impl, | |
| 391 | }, | |
| 392 | ParentSegmentArgs::NotSpecified => DelegationGenerics::generate_all( | |
| 393 | &sig_parent_params[usize::from(!generate_self)..], | |
| 394 | GenericsPosition::Parent, | |
| 395 | trait_impl, | |
| 396 | ), | |
| 397 | ParentSegmentArgs::Invalid => { | |
| 398 | DelegationGenerics { data: vec![], pos: GenericsPosition::Parent, trait_impl } | |
| 359 | 399 | } |
| 360 | } else { | |
| 361 | DelegationGenerics { data: vec![], pos: GenericsPosition::Parent, trait_impl: false } | |
| 362 | 400 | }; |
| 363 | 401 | |
| 364 | let child_generics = if let Some(args) = get_user_args(len - 1) { | |
| 365 | let synth_params_index = | |
| 366 | sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len()); | |
| 402 | let child_generics = if let Some(args) = res.child_args { | |
| 403 | let synth_params_index = sig_child_params | |
| 404 | .iter() | |
| 405 | .position(|p| p.kind.is_synthetic()) | |
| 406 | .unwrap_or(sig_child_params.len()); | |
| 367 | 407 | |
| 368 | let mut slots = | |
| 369 | self.create_slots_from_args(args, &sig_params[..synth_params_index], false); | |
| 408 | let mut slots = Self::create_slots_from_args( | |
| 409 | tcx, | |
| 410 | args, | |
| 411 | &sig_child_params[..synth_params_index], | |
| 412 | trait_impl, | |
| 413 | ); | |
| 370 | 414 | |
| 371 | for synth_param in &sig_params[synth_params_index..] { | |
| 415 | for synth_param in &sig_child_params[synth_params_index..] { | |
| 372 | 416 | slots.push(GenericArgSlot::Generate(synth_param, None)); |
| 373 | 417 | } |
| 374 | 418 | |
| 375 | DelegationGenerics { data: slots, pos: GenericsPosition::Child, trait_impl: false } | |
| 419 | DelegationGenerics { data: slots, pos: GenericsPosition::Child, trait_impl } | |
| 376 | 420 | } else { |
| 377 | DelegationGenerics::generate_all(sig_params, GenericsPosition::Child, false) | |
| 421 | DelegationGenerics::generate_all(sig_child_params, GenericsPosition::Child, trait_impl) | |
| 378 | 422 | }; |
| 379 | 423 | |
| 380 | 424 | GenericsGenerationResults { |
| 381 | 425 | parent: GenericsGenerationResult::new(parent_generics), |
| 382 | 426 | child: GenericsGenerationResult::new(child_generics), |
| 383 | self_ty_propagation_kind: match free_to_trait_delegation { | |
| 384 | true => Some(match qself_is_none { | |
| 427 | self_ty_propagation_kind: match res.free_to_trait_delegation { | |
| 428 | true => Some(match res.qself_is_none { | |
| 385 | 429 | true => hir::DelegationSelfTyPropagationKind::SelfParam, |
| 386 | false => match qself_is_infer { | |
| 430 | false => match res.qself_is_infer { | |
| 387 | 431 | true => hir::DelegationSelfTyPropagationKind::SelfParam, |
| 388 | 432 | // HirId is filled during generic args propagation. |
| 389 | 433 | false => hir::DelegationSelfTyPropagationKind::SelfTy(HirId::INVALID), |
| ... | ... | @@ -403,7 +447,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 403 | 447 | /// infers than generic params then we will not process all infers thus not generating |
| 404 | 448 | /// more generic params then needed (anyway it is an error). |
| 405 | 449 | fn create_slots_from_args( |
| 406 | &self, | |
| 450 | tcx: TyCtxt<'_>, | |
| 407 | 451 | args: &AngleBracketedArgs, |
| 408 | 452 | params: &'hir [ty::GenericParamDef], |
| 409 | 453 | add_first_self: bool, |
| ... | ... | @@ -444,11 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 444 | 488 | (kw::Underscore, kw::UnderscoreLifetime) |
| 445 | 489 | }; |
| 446 | 490 | |
| 447 | self.tcx.dcx().emit_err(DelegationInfersMismatch { | |
| 448 | span: arg.span(), | |
| 449 | actual, | |
| 450 | expected, | |
| 451 | }); | |
| 491 | tcx.dcx().emit_err(DelegationInfersMismatch { span: arg.span(), actual, expected }); | |
| 452 | 492 | } |
| 453 | 493 | |
| 454 | 494 | slots.push(match is_infer { |
| ... | ... | @@ -459,7 +499,42 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 459 | 499 | |
| 460 | 500 | slots |
| 461 | 501 | } |
| 502 | } | |
| 503 | ||
| 504 | impl<'hir> GenericsGenerationResults<'hir> { | |
| 505 | pub(super) fn all_params(&self) -> impl Iterator<Item = hir::GenericParam<'hir>> { | |
| 506 | let parent = self.parent.generics.hir_generics_or_empty().params; | |
| 507 | let child = self.child.generics.hir_generics_or_empty().params; | |
| 508 | ||
| 509 | // Order generics, first we have parent and child lifetimes, | |
| 510 | // then parent and child types and consts. | |
| 511 | // `generics_of` in `rustc_hir_analysis` will order them anyway, | |
| 512 | // however we want the order to be consistent in HIR too. | |
| 513 | parent | |
| 514 | .iter() | |
| 515 | .filter(|p| p.is_lifetime()) | |
| 516 | .chain(child.iter().filter(|p| p.is_lifetime())) | |
| 517 | .chain(parent.iter().filter(|p| !p.is_lifetime())) | |
| 518 | .chain(child.iter().filter(|p| !p.is_lifetime())) | |
| 519 | .copied() | |
| 520 | } | |
| 521 | ||
| 522 | /// As we add hack predicates(`'a: 'a`) for all lifetimes (see `uplift_delegation_generic_params` | |
| 523 | /// and `generate_lifetime_predicate` functions) we need to add them to delegation generics. | |
| 524 | /// Those predicates will not affect resulting predicate inheritance and folding | |
| 525 | /// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature. | |
| 526 | pub(super) fn all_predicates(&self) -> impl Iterator<Item = hir::WherePredicate<'hir>> { | |
| 527 | self.parent | |
| 528 | .generics | |
| 529 | .hir_generics_or_empty() | |
| 530 | .predicates | |
| 531 | .into_iter() | |
| 532 | .chain(self.child.generics.hir_generics_or_empty().predicates) | |
| 533 | .copied() | |
| 534 | } | |
| 535 | } | |
| 462 | 536 | |
| 537 | impl<'hir> LoweringContext<'_, 'hir> { | |
| 463 | 538 | fn uplift_delegation_generic_params( |
| 464 | 539 | &mut self, |
| 465 | 540 | span: Span, |
compiler/rustc_ast_lowering/src/delegation/mod.rs created+558| ... | ... | @@ -0,0 +1,558 @@ |
| 1 | //! This module implements expansion of delegation items with early resolved paths. | |
| 2 | //! It includes a delegation to a free functions: | |
| 3 | //! | |
| 4 | //! ```ignore (illustrative) | |
| 5 | //! reuse module::name { target_expr_template } | |
| 6 | //! ``` | |
| 7 | //! | |
| 8 | //! And delegation to a trait methods: | |
| 9 | //! | |
| 10 | //! ```ignore (illustrative) | |
| 11 | //! reuse <Type as Trait>::name { target_expr_template } | |
| 12 | //! ``` | |
| 13 | //! | |
| 14 | //! After expansion for both cases we get: | |
| 15 | //! | |
| 16 | //! ```ignore (illustrative) | |
| 17 | //! fn name( | |
| 18 | //! arg0: InferDelegation(sig_id, Input(0)), | |
| 19 | //! arg1: InferDelegation(sig_id, Input(1)), | |
| 20 | //! ..., | |
| 21 | //! argN: InferDelegation(sig_id, Input(N)), | |
| 22 | //! ) -> InferDelegation(sig_id, Output) { | |
| 23 | //! callee_path(target_expr_template(arg0), arg1, ..., argN) | |
| 24 | //! } | |
| 25 | //! ``` | |
| 26 | //! | |
| 27 | //! Where `callee_path` is a path in delegation item e.g. `<Type as Trait>::name`. | |
| 28 | //! `sig_id` is a id of item from which the signature is inherited. It may be a delegation | |
| 29 | //! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise. | |
| 30 | //! | |
| 31 | //! Since we do not have a proper way to obtain function type information by path resolution | |
| 32 | //! in AST, we mark each function parameter type as `InferDelegation` and inherit it during | |
| 33 | //! HIR ty lowering. | |
| 34 | //! | |
| 35 | //! Similarly generics, predicates and header are set to the "default" values. | |
| 36 | //! In case of discrepancy with callee function the `UnsupportedDelegation` error will | |
| 37 | //! also be emitted during HIR ty lowering. | |
| 38 | ||
| 39 | use std::iter; | |
| 40 | ||
| 41 | use ast::visit::Visitor; | |
| 42 | use generics::GenericsGenerationResult; | |
| 43 | use hir::HirId; | |
| 44 | use hir::def::Res; | |
| 45 | use rustc_abi::ExternAbi; | |
| 46 | use rustc_ast as ast; | |
| 47 | use rustc_ast::*; | |
| 48 | use rustc_hir::{self as hir, FnDeclFlags}; | |
| 49 | use rustc_middle::ty::Asyncness; | |
| 50 | use rustc_span::def_id::DefId; | |
| 51 | use rustc_span::symbol::kw; | |
| 52 | use rustc_span::{Ident, Span, Symbol, sym}; | |
| 53 | ||
| 54 | use crate::delegation::generics::{GenericsGenerationResults, GenericsPosition}; | |
| 55 | use crate::delegation::resolution::resolver::DelegationResolver; | |
| 56 | use crate::delegation::resolution::{DelegationResolution, ParamInfo}; | |
| 57 | use crate::{ | |
| 58 | AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, | |
| 59 | }; | |
| 60 | ||
| 61 | mod attributes; | |
| 62 | mod generics; | |
| 63 | mod resolution; | |
| 64 | ||
| 65 | pub(crate) struct DelegationResults<'hir> { | |
| 66 | pub body_id: hir::BodyId, | |
| 67 | pub sig: hir::FnSig<'hir>, | |
| 68 | pub ident: Ident, | |
| 69 | pub generics: &'hir hir::Generics<'hir>, | |
| 70 | } | |
| 71 | ||
| 72 | impl<'hir> LoweringContext<'_, 'hir> { | |
| 73 | pub(crate) fn lower_delegation(&mut self, delegation: &Delegation) -> DelegationResults<'hir> { | |
| 74 | let span = self.lower_span(delegation.last_segment_span()); | |
| 75 | ||
| 76 | let resolver = DelegationResolver::new(self); | |
| 77 | let Ok((res, mut generics)) = resolver.resolve_delegation(delegation, span) else { | |
| 78 | return self.generate_delegation_error(span, delegation); | |
| 79 | }; | |
| 80 | ||
| 81 | self.add_attrs_if_needed(&res); | |
| 82 | ||
| 83 | let (body_id, call_expr_id, unused_target_expr) = | |
| 84 | self.lower_delegation_body(delegation, &res, &mut generics); | |
| 85 | ||
| 86 | let decl = self.lower_delegation_decl(&res, &generics, call_expr_id, unused_target_expr); | |
| 87 | ||
| 88 | let sig = self.lower_delegation_sig(res.sig_id, decl, span); | |
| 89 | ||
| 90 | let ident = self.lower_ident(delegation.ident); | |
| 91 | ||
| 92 | let generics = self.arena.alloc(hir::Generics { | |
| 93 | has_where_clause_predicates: false, | |
| 94 | params: self.arena.alloc_from_iter(generics.all_params()), | |
| 95 | predicates: self.arena.alloc_from_iter(generics.all_predicates()), | |
| 96 | span, | |
| 97 | where_clause_span: span, | |
| 98 | }); | |
| 99 | ||
| 100 | DelegationResults { body_id, sig, ident, generics } | |
| 101 | } | |
| 102 | ||
| 103 | fn lower_delegation_decl( | |
| 104 | &mut self, | |
| 105 | res: &DelegationResolution, | |
| 106 | generics: &GenericsGenerationResults<'hir>, | |
| 107 | call_expr_id: HirId, | |
| 108 | unused_target_expr: bool, | |
| 109 | ) -> &'hir hir::FnDecl<'hir> { | |
| 110 | let &DelegationResolution { source, call_path_res, span, sig_id, .. } = res; | |
| 111 | let ParamInfo { param_count, c_variadic, splatted } = res.param_info; | |
| 112 | ||
| 113 | // The last parameter in C variadic functions is skipped in the signature, | |
| 114 | // like during regular lowering. | |
| 115 | let decl_param_count = param_count - c_variadic as usize; | |
| 116 | let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty { | |
| 117 | hir_id: self.next_id(), | |
| 118 | kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( | |
| 119 | sig_id, | |
| 120 | hir::InferDelegationSig::Input(arg), | |
| 121 | )), | |
| 122 | span, | |
| 123 | })); | |
| 124 | ||
| 125 | let output = self.arena.alloc(hir::Ty { | |
| 126 | hir_id: self.next_id(), | |
| 127 | kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig( | |
| 128 | sig_id, | |
| 129 | hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationInfo { | |
| 130 | call_expr_id, | |
| 131 | call_path_res, | |
| 132 | child_seg_id: generics.child.args_segment_id, | |
| 133 | child_seg_id_for_sig: generics.child.segment_id_for_sig(), | |
| 134 | parent_seg_id_for_sig: generics.parent.segment_id_for_sig(), | |
| 135 | self_ty_propagation_kind: generics.self_ty_propagation_kind, | |
| 136 | group_id: { | |
| 137 | let id = match source { | |
| 138 | DelegationSource::Single => None, | |
| 139 | DelegationSource::List(expn_id) => Some(expn_id), | |
| 140 | DelegationSource::Glob => { | |
| 141 | Some(self.tcx.expn_that_defined(self.owner.def_id).expect_local()) | |
| 142 | } | |
| 143 | }; | |
| 144 | ||
| 145 | id.map(|id| (id, unused_target_expr)) | |
| 146 | }, | |
| 147 | })), | |
| 148 | )), | |
| 149 | span, | |
| 150 | }); | |
| 151 | ||
| 152 | self.arena.alloc(hir::FnDecl { | |
| 153 | inputs, | |
| 154 | output: hir::FnRetTy::Return(output), | |
| 155 | fn_decl_kind: FnDeclFlags::default() | |
| 156 | .set_lifetime_elision_allowed(true) | |
| 157 | .set_c_variadic(c_variadic) | |
| 158 | .set_splatted(splatted, inputs.len()) | |
| 159 | .unwrap(), | |
| 160 | }) | |
| 161 | } | |
| 162 | ||
| 163 | fn lower_delegation_sig( | |
| 164 | &mut self, | |
| 165 | sig_id: DefId, | |
| 166 | decl: &'hir hir::FnDecl<'hir>, | |
| 167 | span: Span, | |
| 168 | ) -> hir::FnSig<'hir> { | |
| 169 | let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); | |
| 170 | let asyncness = match self.tcx.asyncness(sig_id) { | |
| 171 | Asyncness::Yes => hir::IsAsync::Async(span), | |
| 172 | Asyncness::No => hir::IsAsync::NotAsync, | |
| 173 | }; | |
| 174 | ||
| 175 | let header = hir::FnHeader { | |
| 176 | safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features { | |
| 177 | hir::HeaderSafety::SafeTargetFeatures | |
| 178 | } else { | |
| 179 | hir::HeaderSafety::Normal(sig.safety()) | |
| 180 | }, | |
| 181 | constness: self.tcx.constness(sig_id), | |
| 182 | asyncness, | |
| 183 | abi: sig.abi(), | |
| 184 | }; | |
| 185 | ||
| 186 | hir::FnSig { decl, header, span } | |
| 187 | } | |
| 188 | ||
| 189 | fn generate_param( | |
| 190 | &mut self, | |
| 191 | is_method: bool, | |
| 192 | idx: usize, | |
| 193 | span: Span, | |
| 194 | ) -> (hir::Param<'hir>, NodeId) { | |
| 195 | let pat_node_id = self.next_node_id(); | |
| 196 | let pat_id = self.lower_node_id(pat_node_id); | |
| 197 | // FIXME(cjgillot) AssocItem currently relies on self parameter being exactly named `self`. | |
| 198 | let name = if is_method && idx == 0 { | |
| 199 | kw::SelfLower | |
| 200 | } else { | |
| 201 | Symbol::intern(&format!("arg{idx}")) | |
| 202 | }; | |
| 203 | let ident = Ident::with_dummy_span(name); | |
| 204 | let pat = self.arena.alloc(hir::Pat { | |
| 205 | hir_id: pat_id, | |
| 206 | kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None), | |
| 207 | span, | |
| 208 | default_binding_modes: false, | |
| 209 | }); | |
| 210 | ||
| 211 | (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id) | |
| 212 | } | |
| 213 | ||
| 214 | fn generate_arg( | |
| 215 | &mut self, | |
| 216 | is_method: bool, | |
| 217 | idx: usize, | |
| 218 | param_id: HirId, | |
| 219 | span: Span, | |
| 220 | ) -> hir::Expr<'hir> { | |
| 221 | // FIXME(cjgillot) AssocItem currently relies on self parameter being exactly named `self`. | |
| 222 | let name = if is_method && idx == 0 { | |
| 223 | kw::SelfLower | |
| 224 | } else { | |
| 225 | Symbol::intern(&format!("arg{idx}")) | |
| 226 | }; | |
| 227 | ||
| 228 | let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment { | |
| 229 | ident: Ident::with_dummy_span(name), | |
| 230 | hir_id: self.next_id(), | |
| 231 | res: Res::Local(param_id), | |
| 232 | args: None, | |
| 233 | infer_args: false, | |
| 234 | delegation_child_segment: false, | |
| 235 | })); | |
| 236 | ||
| 237 | let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); | |
| 238 | self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span) | |
| 239 | } | |
| 240 | ||
| 241 | fn lower_delegation_body( | |
| 242 | &mut self, | |
| 243 | delegation: &Delegation, | |
| 244 | res: &DelegationResolution, | |
| 245 | generics: &mut GenericsGenerationResults<'hir>, | |
| 246 | ) -> (hir::BodyId, HirId, bool) { | |
| 247 | let block = delegation.body.as_deref(); | |
| 248 | let mut call_expr_id = HirId::INVALID; | |
| 249 | let mut unused_target_expr = false; | |
| 250 | ||
| 251 | let block_id = self.lower_body(|this| { | |
| 252 | let &DelegationResolution { | |
| 253 | param_info, span, should_generate_block, is_method, .. | |
| 254 | } = res; | |
| 255 | ||
| 256 | let ParamInfo { param_count, .. } = param_info; | |
| 257 | ||
| 258 | let mut parameters: Vec<hir::Param<'_>> = Vec::with_capacity(param_count); | |
| 259 | let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count); | |
| 260 | let mut stmts: &[hir::Stmt<'hir>] = &[]; | |
| 261 | ||
| 262 | // Consider non-specified target expression as generated, | |
| 263 | // as we do not want to emit error when target expression is | |
| 264 | // not specified. | |
| 265 | unused_target_expr = block.is_some() && (param_count == 0 || !should_generate_block); | |
| 266 | ||
| 267 | for idx in 0..param_count { | |
| 268 | let (param, pat_node_id) = this.generate_param(is_method, idx, span); | |
| 269 | parameters.push(param); | |
| 270 | ||
| 271 | let generate_arg = | |
| 272 | |this: &mut Self| this.generate_arg(is_method, idx, param.pat.hir_id, span); | |
| 273 | ||
| 274 | let arg = if let Some(block) = block | |
| 275 | && idx == 0 | |
| 276 | && should_generate_block | |
| 277 | { | |
| 278 | let mut self_resolver = SelfResolver { | |
| 279 | ctxt: this, | |
| 280 | path_id: delegation.id, | |
| 281 | self_param_id: pat_node_id, | |
| 282 | }; | |
| 283 | self_resolver.visit_block(block); | |
| 284 | // Target expr needs to lower `self` path. | |
| 285 | this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); | |
| 286 | ||
| 287 | // Lower with `HirId::INVALID` as we will use only expr and stmts. | |
| 288 | // FIXME(fn_delegation): Alternatives for target expression lowering: | |
| 289 | // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600. | |
| 290 | let block = this.lower_block_noalloc(HirId::INVALID, block, false); | |
| 291 | ||
| 292 | stmts = block.stmts; | |
| 293 | ||
| 294 | // The behavior of the delegation's target expression differs from the | |
| 295 | // behavior of the usual block, where if there is no final expression | |
| 296 | // the `()` is returned. In case of the similar situation in delegation | |
| 297 | // (no final expression) we propagate first argument instead of replacing | |
| 298 | // it with `()`. | |
| 299 | if let Some(&expr) = block.expr { expr } else { generate_arg(this) } | |
| 300 | } else { | |
| 301 | generate_arg(this) | |
| 302 | }; | |
| 303 | ||
| 304 | args.push(arg); | |
| 305 | } | |
| 306 | ||
| 307 | let (final_expr, hir_id) = | |
| 308 | this.finalize_body_lowering(delegation, stmts, args, res, generics, span); | |
| 309 | ||
| 310 | call_expr_id = hir_id; | |
| 311 | ||
| 312 | (this.arena.alloc_from_iter(parameters), final_expr) | |
| 313 | }); | |
| 314 | ||
| 315 | debug_assert_ne!(call_expr_id, HirId::INVALID); | |
| 316 | ||
| 317 | (block_id, call_expr_id, unused_target_expr) | |
| 318 | } | |
| 319 | ||
| 320 | fn finalize_body_lowering( | |
| 321 | &mut self, | |
| 322 | delegation: &Delegation, | |
| 323 | stmts: &'hir [hir::Stmt<'hir>], | |
| 324 | args: Vec<hir::Expr<'hir>>, | |
| 325 | res: &DelegationResolution, | |
| 326 | generics: &mut GenericsGenerationResults<'hir>, | |
| 327 | span: Span, | |
| 328 | ) -> (hir::Expr<'hir>, HirId) { | |
| 329 | let path = self.lower_qpath( | |
| 330 | delegation.id, | |
| 331 | &delegation.qself, | |
| 332 | &delegation.path, | |
| 333 | ParamMode::Optional, | |
| 334 | AllowReturnTypeNotation::No, | |
| 335 | ImplTraitContext::Disallowed(ImplTraitPosition::Path), | |
| 336 | None, | |
| 337 | ); | |
| 338 | ||
| 339 | let new_path = match path { | |
| 340 | hir::QPath::Resolved(ty, path) => { | |
| 341 | let mut new_path = path.clone(); | |
| 342 | let len = new_path.segments.len(); | |
| 343 | ||
| 344 | new_path.segments = self.arena.alloc_from_iter( | |
| 345 | new_path.segments.iter().enumerate().map(|(idx, segment)| { | |
| 346 | if idx + 2 == len { | |
| 347 | self.process_segment(span, segment, &mut generics.parent) | |
| 348 | } else if idx + 1 == len { | |
| 349 | self.process_segment(span, segment, &mut generics.child) | |
| 350 | } else { | |
| 351 | segment.clone() | |
| 352 | } | |
| 353 | }), | |
| 354 | ); | |
| 355 | ||
| 356 | // Explicitly create `Self` self-type in case of infers or static | |
| 357 | // free-to-trait reuses. | |
| 358 | let ty = match generics.self_ty_propagation_kind { | |
| 359 | Some(hir::DelegationSelfTyPropagationKind::SelfParam) => { | |
| 360 | let self_param = generics.parent.generics.find_self_param(); | |
| 361 | let path = self.create_generic_arg_path(self_param); | |
| 362 | let kind = hir::TyKind::Path(path); | |
| 363 | ||
| 364 | let ty = match ty { | |
| 365 | Some(ty) => hir::Ty { kind, ..ty.clone() }, | |
| 366 | None => hir::Ty { kind, hir_id: self.next_id(), span }, | |
| 367 | }; | |
| 368 | ||
| 369 | Some(&*self.arena.alloc(ty)) | |
| 370 | } | |
| 371 | _ => ty, | |
| 372 | }; | |
| 373 | ||
| 374 | hir::QPath::Resolved(ty, self.arena.alloc(new_path)) | |
| 375 | } | |
| 376 | hir::QPath::TypeRelative(..) => unreachable!("until inherent methods are supported"), | |
| 377 | }; | |
| 378 | ||
| 379 | if let Some(hir::DelegationSelfTyPropagationKind::SelfTy(id)) = | |
| 380 | generics.self_ty_propagation_kind.as_mut() | |
| 381 | { | |
| 382 | *id = match new_path { | |
| 383 | hir::QPath::Resolved(ty, _) => { | |
| 384 | ty.expect("must contain self type as `SelfTy` propagation kind is specified") | |
| 385 | } | |
| 386 | hir::QPath::TypeRelative(ty, _) => ty, | |
| 387 | } | |
| 388 | .hir_id; | |
| 389 | } | |
| 390 | ||
| 391 | let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span)); | |
| 392 | let args = self.arena.alloc_from_iter(args); | |
| 393 | let call = self.mk_expr(hir::ExprKind::Call(callee_path, args), span); | |
| 394 | ||
| 395 | let expr = if let Some((parent, of_trait)) = res.output_self_mapping { | |
| 396 | let res = Res::SelfTyAlias { alias_to: parent.to_def_id(), is_trait_impl: of_trait }; | |
| 397 | let ident = Ident::new(kw::SelfUpper, span); | |
| 398 | let path = self.create_resolved_path(res, ident, span); | |
| 399 | ||
| 400 | // FIXME(fn_delegation): add default `..` for all other fields. | |
| 401 | let initializer = hir::ExprKind::Struct( | |
| 402 | self.arena.alloc(path), | |
| 403 | self.arena.alloc_slice(&[hir::ExprField { | |
| 404 | hir_id: self.next_id(), | |
| 405 | is_shorthand: false, | |
| 406 | ident: Ident::new(sym::integer(0), span), | |
| 407 | expr: self.arena.alloc(call), | |
| 408 | span, | |
| 409 | }]), | |
| 410 | hir::StructTailExpr::None, | |
| 411 | ); | |
| 412 | ||
| 413 | self.arena.alloc(self.mk_expr(initializer, span)) | |
| 414 | } else { | |
| 415 | self.arena.alloc(call) | |
| 416 | }; | |
| 417 | ||
| 418 | let block = self.arena.alloc(hir::Block { | |
| 419 | stmts, | |
| 420 | expr: Some(expr), | |
| 421 | hir_id: self.next_id(), | |
| 422 | rules: hir::BlockCheckMode::DefaultBlock, | |
| 423 | span, | |
| 424 | targeted_by_break: false, | |
| 425 | }); | |
| 426 | ||
| 427 | (self.mk_expr(hir::ExprKind::Block(block, None), span), call.hir_id) | |
| 428 | } | |
| 429 | ||
| 430 | fn process_segment( | |
| 431 | &mut self, | |
| 432 | span: Span, | |
| 433 | segment: &hir::PathSegment<'hir>, | |
| 434 | result: &mut GenericsGenerationResult<'hir>, | |
| 435 | ) -> hir::PathSegment<'hir> { | |
| 436 | let infer_indices = result.generics.infer_indices(); | |
| 437 | result.generics.into_hir_generics(self, span); | |
| 438 | ||
| 439 | let mut segment = segment.clone(); | |
| 440 | let mut args_iter = result.generics.create_args_iterator(); | |
| 441 | ||
| 442 | let new_args = segment | |
| 443 | .args | |
| 444 | .filter(|args| !args.is_empty()) | |
| 445 | .map(|args| { | |
| 446 | self.arena.alloc_from_iter(args.args.iter().enumerate().map(|(idx, arg)| { | |
| 447 | if infer_indices.contains(&idx) { | |
| 448 | args_iter.next(self, |_| arg.hir_id()).expect("arg must exist for infer") | |
| 449 | } else { | |
| 450 | *arg | |
| 451 | } | |
| 452 | })) | |
| 453 | }) | |
| 454 | .unwrap_or_else(|| self.arena.alloc_from_iter(args_iter.consume_all(self))); | |
| 455 | ||
| 456 | // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). | |
| 457 | segment.args = (!new_args.is_empty()).then(|| { | |
| 458 | &*self.arena.alloc(hir::GenericArgs { | |
| 459 | args: new_args, | |
| 460 | constraints: &[], | |
| 461 | parenthesized: hir::GenericArgsParentheses::No, | |
| 462 | span_ext: segment.args.map_or(span, |args| args.span_ext), | |
| 463 | }) | |
| 464 | }); | |
| 465 | ||
| 466 | result.args_segment_id = segment.hir_id; | |
| 467 | result.use_for_sig_inheritance = !result.generics.is_trait_impl(); | |
| 468 | ||
| 469 | segment.delegation_child_segment = result.generics.pos() == GenericsPosition::Child; | |
| 470 | ||
| 471 | segment | |
| 472 | } | |
| 473 | ||
| 474 | fn generate_delegation_error( | |
| 475 | &mut self, | |
| 476 | span: Span, | |
| 477 | delegation: &Delegation, | |
| 478 | ) -> DelegationResults<'hir> { | |
| 479 | let decl = self.arena.alloc(hir::FnDecl::dummy(span)); | |
| 480 | ||
| 481 | let header = self.generate_header_error(); | |
| 482 | let sig = hir::FnSig { decl, header, span }; | |
| 483 | ||
| 484 | let ident = self.lower_ident(delegation.ident); | |
| 485 | ||
| 486 | let body_id = self.lower_body(|this| { | |
| 487 | let path = this.lower_qpath( | |
| 488 | delegation.id, | |
| 489 | &delegation.qself, | |
| 490 | &delegation.path, | |
| 491 | ParamMode::Optional, | |
| 492 | AllowReturnTypeNotation::No, | |
| 493 | ImplTraitContext::Disallowed(ImplTraitPosition::Path), | |
| 494 | None, | |
| 495 | ); | |
| 496 | ||
| 497 | let callee_path = this.arena.alloc(this.mk_expr(hir::ExprKind::Path(path), span)); | |
| 498 | let args = if let Some(block) = &delegation.body { | |
| 499 | this.arena.alloc_slice(&[this.lower_block_expr(block)]) | |
| 500 | } else { | |
| 501 | &mut [] | |
| 502 | }; | |
| 503 | ||
| 504 | let call = this.arena.alloc(this.mk_expr(hir::ExprKind::Call(callee_path, args), span)); | |
| 505 | ||
| 506 | let block = this.arena.alloc(hir::Block { | |
| 507 | stmts: &[], | |
| 508 | expr: Some(call), | |
| 509 | hir_id: this.next_id(), | |
| 510 | rules: hir::BlockCheckMode::DefaultBlock, | |
| 511 | span, | |
| 512 | targeted_by_break: false, | |
| 513 | }); | |
| 514 | ||
| 515 | (&[], this.mk_expr(hir::ExprKind::Block(block, None), span)) | |
| 516 | }); | |
| 517 | ||
| 518 | let generics = hir::Generics::empty(); | |
| 519 | DelegationResults { ident, generics, body_id, sig } | |
| 520 | } | |
| 521 | ||
| 522 | fn generate_header_error(&self) -> hir::FnHeader { | |
| 523 | hir::FnHeader { | |
| 524 | safety: hir::Safety::Safe.into(), | |
| 525 | constness: hir::Constness::NotConst, | |
| 526 | asyncness: hir::IsAsync::NotAsync, | |
| 527 | abi: ExternAbi::Rust, | |
| 528 | } | |
| 529 | } | |
| 530 | ||
| 531 | #[inline] | |
| 532 | fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> { | |
| 533 | hir::Expr { hir_id: self.next_id(), kind, span } | |
| 534 | } | |
| 535 | } | |
| 536 | ||
| 537 | struct SelfResolver<'a, 'b, 'hir> { | |
| 538 | ctxt: &'a mut LoweringContext<'b, 'hir>, | |
| 539 | path_id: NodeId, | |
| 540 | self_param_id: NodeId, | |
| 541 | } | |
| 542 | ||
| 543 | impl SelfResolver<'_, '_, '_> { | |
| 544 | fn try_replace_id(&mut self, id: NodeId) { | |
| 545 | if let Some(res) = self.ctxt.get_partial_res(id) | |
| 546 | && let Some(Res::Local(sig_id)) = res.full_res() | |
| 547 | && sig_id == self.path_id | |
| 548 | { | |
| 549 | self.ctxt.partial_res_overrides.insert(id, self.self_param_id); | |
| 550 | } | |
| 551 | } | |
| 552 | } | |
| 553 | ||
| 554 | impl<'ast> Visitor<'ast> for SelfResolver<'_, '_, '_> { | |
| 555 | fn visit_id(&mut self, id: NodeId) { | |
| 556 | self.try_replace_id(id); | |
| 557 | } | |
| 558 | } |
compiler/rustc_ast_lowering/src/delegation/resolution.rs created+264| ... | ... | @@ -0,0 +1,264 @@ |
| 1 | use std::ops::ControlFlow; | |
| 2 | ||
| 3 | use ast::visit::Visitor; | |
| 4 | use hir::def::DefKind; | |
| 5 | use rustc_ast as ast; | |
| 6 | use rustc_ast::*; | |
| 7 | use rustc_data_structures::fx::FxHashSet; | |
| 8 | use rustc_hir as hir; | |
| 9 | use rustc_middle::span_bug; | |
| 10 | use rustc_span::def_id::{DefId, LocalDefId}; | |
| 11 | use rustc_span::{ErrorGuaranteed, Span}; | |
| 12 | ||
| 13 | use crate::delegation::generics::GenericsGenerationResults; | |
| 14 | use crate::delegation::resolution::resolver::DelegationResolver; | |
| 15 | use crate::diagnostics::{ | |
| 16 | CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion, | |
| 17 | DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee, | |
| 18 | }; | |
| 19 | ||
| 20 | /// Summary info about function parameters. | |
| 21 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | |
| 22 | pub(super) struct ParamInfo { | |
| 23 | /// The number of function parameters, including any C variadic `...` parameter. | |
| 24 | pub param_count: usize, | |
| 25 | ||
| 26 | /// Whether the function arguments end in a C variadic `...` parameter. | |
| 27 | pub c_variadic: bool, | |
| 28 | ||
| 29 | /// The index of the splatted parameter, if any. | |
| 30 | pub splatted: Option<u8>, | |
| 31 | } | |
| 32 | ||
| 33 | pub(super) struct DelegationResolution { | |
| 34 | pub sig_id: DefId, | |
| 35 | pub is_method: bool, | |
| 36 | pub param_info: ParamInfo, | |
| 37 | pub span: Span, | |
| 38 | pub should_generate_block: bool, | |
| 39 | pub call_path_res: Option<DefId>, | |
| 40 | pub source: DelegationSource, | |
| 41 | pub output_self_mapping: Option<(LocalDefId, bool)>, | |
| 42 | } | |
| 43 | ||
| 44 | pub(super) mod resolver { | |
| 45 | use rustc_ast::NodeId; | |
| 46 | use rustc_hir::def_id::{DefId, LocalDefId}; | |
| 47 | use rustc_middle::ty::TyCtxt; | |
| 48 | ||
| 49 | use crate::LoweringContext; | |
| 50 | ||
| 51 | /// Abstracts operations that are needed for delegation's resolution, so resolution | |
| 52 | /// is independent of `LoweringContext`. Placed in a separate module so `LoweringContext` | |
| 53 | /// can not be accessed directly. | |
| 54 | pub(crate) struct DelegationResolver<'a, 'hir>(&'a LoweringContext<'a, 'hir>); | |
| 55 | ||
| 56 | impl<'a, 'tcx> DelegationResolver<'a, 'tcx> { | |
| 57 | pub(crate) fn new(ctx: &'a LoweringContext<'a, 'tcx>) -> Self { | |
| 58 | DelegationResolver(ctx) | |
| 59 | } | |
| 60 | ||
| 61 | #[inline] | |
| 62 | pub(crate) fn tcx(&self) -> TyCtxt<'tcx> { | |
| 63 | self.0.tcx | |
| 64 | } | |
| 65 | ||
| 66 | #[inline] | |
| 67 | pub(crate) fn owner_id(&self) -> LocalDefId { | |
| 68 | self.0.owner.def_id | |
| 69 | } | |
| 70 | ||
| 71 | /// (from `tests\ui\delegation\target-expr-removal-defs-inside.rs`): | |
| 72 | /// ```rust | |
| 73 | /// reuse impl Trait for S1 { | |
| 74 | /// some::path::<{ fn foo() {} }>::xd(); | |
| 75 | /// fn foo() {} | |
| 76 | /// self.0 | |
| 77 | /// } | |
| 78 | /// ``` | |
| 79 | /// | |
| 80 | /// Constant from unresolved path will be in `node_id_to_def_id`, | |
| 81 | /// `fn foo() {}` will not be in `node_id_to_def_id` but will be in `owners`, | |
| 82 | /// both have `LocalDefId`, so we check those two maps. | |
| 83 | #[inline] | |
| 84 | pub(crate) fn is_definition(&self, id: NodeId) -> bool { | |
| 85 | self.0.resolver.owners.contains_key(&id) | |
| 86 | || self.0.owner.node_id_to_def_id.contains_key(&id) | |
| 87 | } | |
| 88 | ||
| 89 | #[inline] | |
| 90 | pub(crate) fn get_resolution_id(&self, id: NodeId) -> Option<DefId> { | |
| 91 | self.0.get_partial_res(id).and_then(|r| r.expect_full_res().opt_def_id()) | |
| 92 | } | |
| 93 | } | |
| 94 | } | |
| 95 | ||
| 96 | impl<'tcx> DelegationResolver<'_, 'tcx> { | |
| 97 | pub(super) fn resolve_delegation( | |
| 98 | &self, | |
| 99 | delegation: &Delegation, | |
| 100 | span: Span, | |
| 101 | ) -> Result<(DelegationResolution, GenericsGenerationResults<'tcx>), ErrorGuaranteed> { | |
| 102 | let tcx = self.tcx(); | |
| 103 | let def_id = self.owner_id(); | |
| 104 | ||
| 105 | // Delegation can be missing from the `delegations_resolutions` table | |
| 106 | // in illegal places such as function bodies in extern blocks (see #151356). | |
| 107 | let sig_id = tcx | |
| 108 | .resolutions(()) | |
| 109 | .delegation_infos | |
| 110 | .get(&def_id) | |
| 111 | .map(|info| { | |
| 112 | info.resolution_id.and_then(|id| self.check_for_cycles(id, span).map(|_| id)) | |
| 113 | }) | |
| 114 | .unwrap_or_else(|| { | |
| 115 | Err(tcx.dcx().span_delayed_bug( | |
| 116 | span, | |
| 117 | format!("delegation resolution record was not found for {:?}", def_id), | |
| 118 | )) | |
| 119 | })?; | |
| 120 | ||
| 121 | let is_method = match tcx.def_kind(sig_id) { | |
| 122 | DefKind::Fn => false, | |
| 123 | DefKind::AssocFn => tcx.associated_item(sig_id).is_method(), | |
| 124 | _ => span_bug!(span, "unexpected DefKind for delegation item"), | |
| 125 | }; | |
| 126 | ||
| 127 | let sig = tcx.fn_sig(sig_id).skip_binder().skip_binder(); | |
| 128 | let param_count = sig.inputs().len() + usize::from(sig.c_variadic()); | |
| 129 | ||
| 130 | let res = DelegationResolution { | |
| 131 | is_method, | |
| 132 | span, | |
| 133 | sig_id, | |
| 134 | // FIXME(splat): use `sig.splatted()` once FnSig has it | |
| 135 | param_info: ParamInfo { param_count, c_variadic: sig.c_variadic(), splatted: None }, | |
| 136 | should_generate_block: self.check_block_soundness( | |
| 137 | delegation, | |
| 138 | sig_id, | |
| 139 | is_method, | |
| 140 | param_count, | |
| 141 | )?, | |
| 142 | source: delegation.source, | |
| 143 | call_path_res: self.get_resolution_id(delegation.id), | |
| 144 | output_self_mapping: self.should_map_return_value(delegation), | |
| 145 | }; | |
| 146 | ||
| 147 | Ok((res, self.resolve_and_generate_generics(delegation, sig_id))) | |
| 148 | } | |
| 149 | ||
| 150 | fn check_for_cycles(&self, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> { | |
| 151 | let tcx = self.tcx(); | |
| 152 | let mut visited: FxHashSet<DefId> = Default::default(); | |
| 153 | ||
| 154 | loop { | |
| 155 | visited.insert(def_id); | |
| 156 | ||
| 157 | // If def_id is in local crate and it corresponds to another delegation | |
| 158 | // it means that we refer to another delegation as a callee, so in order to obtain | |
| 159 | // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it. | |
| 160 | if let Some(local_id) = def_id.as_local() | |
| 161 | && let Some(info) = tcx.resolutions(()).delegation_infos.get(&local_id) | |
| 162 | && let Ok(id) = info.resolution_id | |
| 163 | { | |
| 164 | def_id = id; | |
| 165 | if visited.contains(&def_id) { | |
| 166 | return Err(match visited.len() { | |
| 167 | 1 => tcx.dcx().emit_err(UnresolvedDelegationCallee { span }), | |
| 168 | _ => tcx.dcx().emit_err(CycleInDelegationSignatureResolution { span }), | |
| 169 | }); | |
| 170 | } | |
| 171 | } else { | |
| 172 | return Ok(()); | |
| 173 | } | |
| 174 | } | |
| 175 | } | |
| 176 | ||
| 177 | fn check_block_soundness( | |
| 178 | &self, | |
| 179 | delegation: &Delegation, | |
| 180 | sig_id: DefId, | |
| 181 | is_method: bool, | |
| 182 | param_count: usize, | |
| 183 | ) -> Result<bool, ErrorGuaranteed> { | |
| 184 | let tcx = self.tcx(); | |
| 185 | let should_generate_block = is_method | |
| 186 | || matches!(tcx.def_kind(sig_id), DefKind::Fn) | |
| 187 | || matches!(delegation.source, DelegationSource::Single); | |
| 188 | ||
| 189 | let Some(block) = &delegation.body else { return Ok(should_generate_block) }; | |
| 190 | ||
| 191 | // Report an error if user has explicitly specified delegation's target expression | |
| 192 | // in a single delegation when reused function has no params. | |
| 193 | if param_count == 0 && should_generate_block { | |
| 194 | let err = DelegationBlockSpecifiedWhenNoParams { span: block.span }; | |
| 195 | return Err(tcx.dcx().emit_err(err)); | |
| 196 | } | |
| 197 | ||
| 198 | struct DefinitionsFinder<'a, 'hir> { | |
| 199 | ctx: &'a DelegationResolver<'a, 'hir>, | |
| 200 | } | |
| 201 | ||
| 202 | impl<'a> Visitor<'a> for DefinitionsFinder<'a, '_> { | |
| 203 | type Result = ControlFlow<()>; | |
| 204 | ||
| 205 | fn visit_id(&mut self, id: NodeId) -> Self::Result { | |
| 206 | match self.ctx.is_definition(id) { | |
| 207 | true => ControlFlow::Break(()), | |
| 208 | false => ControlFlow::Continue(()), | |
| 209 | } | |
| 210 | } | |
| 211 | } | |
| 212 | ||
| 213 | let mut collector = DefinitionsFinder { ctx: self }; | |
| 214 | ||
| 215 | let contains_defs = collector.visit_block(block).is_break(); | |
| 216 | ||
| 217 | // If there are definitions inside and we can't delete target expression, then report an error. | |
| 218 | // FIXME(fn_delegation): support deletion of target expression with defs inside. | |
| 219 | if should_generate_block || !contains_defs { | |
| 220 | Ok(should_generate_block) | |
| 221 | } else { | |
| 222 | Err(tcx.dcx().emit_err(DelegationAttemptedBlockWithDefsDeletion { span: block.span })) | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 226 | fn should_map_return_value(&self, delegation: &Delegation) -> Option<(LocalDefId, bool)> { | |
| 227 | // Heuristic: don't do wrapping if there is no target expression. | |
| 228 | if delegation.body.is_none() { | |
| 229 | return None; | |
| 230 | } | |
| 231 | ||
| 232 | let tcx = self.tcx(); | |
| 233 | let parent = tcx.local_parent(self.owner_id()); | |
| 234 | let parent_kind = tcx.def_kind(parent); | |
| 235 | ||
| 236 | // Apply wrapping for delegations inside | |
| 237 | // 1) Trait impls, as the return type of both signature function | |
| 238 | // and generated delegation has `Self` generic param returned | |
| 239 | // (checked below). | |
| 240 | // FIXME(fn_delegation): think of enabling wrapping in more scenarios: | |
| 241 | // trait-(impl)-to-free | |
| 242 | // trait-(impl)-to-inherent | |
| 243 | // inherent-to-free | |
| 244 | // 2) Inherent methods when delegating to trait, as we change the type of | |
| 245 | // `Self` to type of struct or enum we delegate from. | |
| 246 | if !matches!(tcx.def_kind(parent), DefKind::Impl { .. }) { | |
| 247 | return None; | |
| 248 | } | |
| 249 | ||
| 250 | let is_trait_impl = parent_kind == DefKind::Impl { of_trait: true }; | |
| 251 | ||
| 252 | // Check that delegation path resolves to a trait AssocFn, not to a free method. | |
| 253 | Some((parent, is_trait_impl)).filter(|_| { | |
| 254 | self.get_resolution_id(delegation.id).is_some_and(|id| { | |
| 255 | tcx.def_kind(id) == DefKind::AssocFn | |
| 256 | // Check that the return type of the callee is `Self` param. | |
| 257 | // After previous check we are sure that `sig_id` and `delegation.id` | |
| 258 | // point to the same function. | |
| 259 | && tcx.def_kind(tcx.parent(id)) == DefKind::Trait | |
| 260 | && tcx.fn_sig(id).skip_binder().output().skip_binder().is_param(0) | |
| 261 | }) | |
| 262 | }) | |
| 263 | } | |
| 264 | } |
compiler/rustc_ast_lowering/src/item.rs+3-3| ... | ... | @@ -567,7 +567,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 567 | 567 | hir::ItemKind::Macro(ident, macro_def, macro_kinds) |
| 568 | 568 | } |
| 569 | 569 | ItemKind::Delegation(delegation) => { |
| 570 | let delegation_results = self.lower_delegation(delegation, id); | |
| 570 | let delegation_results = self.lower_delegation(delegation); | |
| 571 | 571 | hir::ItemKind::Fn { |
| 572 | 572 | sig: delegation_results.sig, |
| 573 | 573 | ident: delegation_results.ident, |
| ... | ... | @@ -1052,7 +1052,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 1052 | 1052 | (*ident, generics, kind, ty.is_some()) |
| 1053 | 1053 | } |
| 1054 | 1054 | AssocItemKind::Delegation(delegation) => { |
| 1055 | let delegation_results = self.lower_delegation(delegation, i.id); | |
| 1055 | let delegation_results = self.lower_delegation(delegation); | |
| 1056 | 1056 | let item_kind = hir::TraitItemKind::Fn( |
| 1057 | 1057 | delegation_results.sig, |
| 1058 | 1058 | hir::TraitFn::Provided(delegation_results.body_id), |
| ... | ... | @@ -1264,7 +1264,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 1264 | 1264 | ) |
| 1265 | 1265 | } |
| 1266 | 1266 | AssocItemKind::Delegation(delegation) => { |
| 1267 | let delegation_results = self.lower_delegation(delegation, i.id); | |
| 1267 | let delegation_results = self.lower_delegation(delegation); | |
| 1268 | 1268 | ( |
| 1269 | 1269 | delegation.ident, |
| 1270 | 1270 | ( |
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs+2-2| ... | ... | @@ -585,11 +585,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { |
| 585 | 585 | NllRegionVariableOrigin::FreeRegion, |
| 586 | 586 | outlived_region, |
| 587 | 587 | ); |
| 588 | let BlameConstraint { category, from_closure, cause, .. } = blame_constraint; | |
| 588 | let BlameConstraint { category, from_closure, span, .. } = blame_constraint; | |
| 589 | 589 | |
| 590 | 590 | let outlived_fr_name = self.give_region_a_name(outlived_region); |
| 591 | 591 | |
| 592 | (category, from_closure, cause.span, outlived_fr_name, path) | |
| 592 | (category, from_closure, span, outlived_fr_name, path) | |
| 593 | 593 | } |
| 594 | 594 | |
| 595 | 595 | /// Returns structured explanation for *why* the borrow contains the |
compiler/rustc_borrowck/src/diagnostics/region_errors.rs+7-7| ... | ... | @@ -414,8 +414,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 414 | 414 | }; |
| 415 | 415 | |
| 416 | 416 | // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. |
| 417 | let cause = | |
| 418 | self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid).0.cause; | |
| 417 | let (blame_constraint, path) = | |
| 418 | self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid); | |
| 419 | let cause = blame_constraint.to_obligation_cause_from_path(&path); | |
| 419 | 420 | |
| 420 | 421 | // FIXME these methods should have better names, and also probably not be this generic. |
| 421 | 422 | // FIXME note that we *throw away* the error element here! We probably want to |
| ... | ... | @@ -448,17 +449,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 448 | 449 | |
| 449 | 450 | let (blame_constraint, path) = |
| 450 | 451 | self.regioncx.best_blame_constraint(fr, fr_origin, outlived_fr); |
| 451 | let BlameConstraint { category, cause, variance_info, .. } = blame_constraint; | |
| 452 | let BlameConstraint { category, span, variance_info, .. } = blame_constraint; | |
| 452 | 453 | |
| 453 | debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); | |
| 454 | debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info); | |
| 454 | 455 | |
| 455 | 456 | // Check if we can use one of the "nice region errors". |
| 456 | 457 | if let (Some(f), Some(o)) = |
| 457 | 458 | (self.regioncx.to_error_region(fr), self.regioncx.to_error_region(outlived_fr)) |
| 458 | 459 | { |
| 459 | 460 | let infer_err = self.infcx.err_ctxt(); |
| 460 | let nice = | |
| 461 | NiceRegionError::new_from_span(&infer_err, self.mir_def_id(), cause.span, o, f); | |
| 461 | let nice = NiceRegionError::new_from_span(&infer_err, self.mir_def_id(), span, o, f); | |
| 462 | 462 | if let Some(diag) = nice.try_report_from_nll() { |
| 463 | 463 | self.buffer_error(diag); |
| 464 | 464 | return; |
| ... | ... | @@ -475,7 +475,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 475 | 475 | fr_is_local, outlived_fr_is_local, category |
| 476 | 476 | ); |
| 477 | 477 | |
| 478 | let errci = ErrorConstraintInfo { fr, outlived_fr, category, span: cause.span }; | |
| 478 | let errci = ErrorConstraintInfo { fr, outlived_fr, category, span }; | |
| 479 | 479 | |
| 480 | 480 | let mut diag = match (category, fr_is_local, outlived_fr_is_local) { |
| 481 | 481 | (ConstraintCategory::SolverRegionConstraint(span), _, _) => { |
compiler/rustc_borrowck/src/region_infer/mod.rs+28-21| ... | ... | @@ -1346,7 +1346,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { |
| 1346 | 1346 | propagated_outlives_requirements.push(ClosureOutlivesRequirement { |
| 1347 | 1347 | subject: ClosureOutlivesSubject::Region(fr_minus), |
| 1348 | 1348 | outlived_free_region: fr_plus, |
| 1349 | blame_span: blame_constraint.cause.span, | |
| 1349 | blame_span: blame_constraint.span, | |
| 1350 | 1350 | category: blame_constraint.category, |
| 1351 | 1351 | }); |
| 1352 | 1352 | } |
| ... | ... | @@ -1652,24 +1652,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { |
| 1652 | 1652 | .collect::<Vec<_>>() |
| 1653 | 1653 | ); |
| 1654 | 1654 | |
| 1655 | // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. | |
| 1656 | // Instead, we use it to produce an improved `ObligationCauseCode`. | |
| 1657 | // FIXME - determine what we should do if we encounter multiple | |
| 1658 | // `ConstraintCategory::Predicate` constraints. Currently, we just pick the first one. | |
| 1659 | let cause_code = path | |
| 1660 | .iter() | |
| 1661 | .find_map(|constraint| { | |
| 1662 | if let ConstraintCategory::Predicate(predicate_span) = constraint.category { | |
| 1663 | // We currently do not store the `DefId` in the `ConstraintCategory` | |
| 1664 | // for performances reasons. The error reporting code used by NLL only | |
| 1665 | // uses the span, so this doesn't cause any problems at the moment. | |
| 1666 | Some(ObligationCauseCode::WhereClause(CRATE_DEF_ID.to_def_id(), predicate_span)) | |
| 1667 | } else { | |
| 1668 | None | |
| 1669 | } | |
| 1670 | }) | |
| 1671 | .unwrap_or_else(|| ObligationCauseCode::Misc); | |
| 1672 | ||
| 1673 | 1655 | // When reporting an error, there is typically a chain of constraints leading from some |
| 1674 | 1656 | // "source" region which must outlive some "target" region. |
| 1675 | 1657 | // In most cases, we prefer to "blame" the constraints closer to the target -- |
| ... | ... | @@ -1836,7 +1818,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { |
| 1836 | 1818 | let blame_constraint = BlameConstraint { |
| 1837 | 1819 | category: best_constraint.category, |
| 1838 | 1820 | from_closure: best_constraint.from_closure, |
| 1839 | cause: ObligationCause::new(best_constraint.span, CRATE_DEF_ID, cause_code.clone()), | |
| 1821 | span: best_constraint.span, | |
| 1840 | 1822 | variance_info: best_constraint.variance_info, |
| 1841 | 1823 | }; |
| 1842 | 1824 | (blame_constraint, path) |
| ... | ... | @@ -1917,6 +1899,31 @@ impl<'tcx> RegionInferenceContext<'tcx> { |
| 1917 | 1899 | pub(crate) struct BlameConstraint<'tcx> { |
| 1918 | 1900 | pub category: ConstraintCategory<'tcx>, |
| 1919 | 1901 | pub from_closure: bool, |
| 1920 | pub cause: ObligationCause<'tcx>, | |
| 1902 | pub span: Span, | |
| 1921 | 1903 | pub variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, |
| 1922 | 1904 | } |
| 1905 | ||
| 1906 | impl<'tcx> BlameConstraint<'tcx> { | |
| 1907 | pub(crate) fn to_obligation_cause_from_path( | |
| 1908 | &self, | |
| 1909 | path: &[OutlivesConstraint<'tcx>], | |
| 1910 | ) -> ObligationCause<'tcx> { | |
| 1911 | // FIXME - determine what we should do if we encounter multiple | |
| 1912 | // `ConstraintCategory::Predicate` constraints. Currently, we just pick the first one. | |
| 1913 | let cause_code = path | |
| 1914 | .iter() | |
| 1915 | .find_map(|constraint| { | |
| 1916 | if let ConstraintCategory::Predicate(predicate_span) = constraint.category { | |
| 1917 | // We currently do not store the `DefId` in the `ConstraintCategory` | |
| 1918 | // for performances reasons. The error reporting code used by NLL only | |
| 1919 | // uses the span, so this doesn't cause any problems at the moment. | |
| 1920 | Some(ObligationCauseCode::WhereClause(CRATE_DEF_ID.to_def_id(), predicate_span)) | |
| 1921 | } else { | |
| 1922 | None | |
| 1923 | } | |
| 1924 | }) | |
| 1925 | .unwrap_or_else(|| ObligationCauseCode::Misc); | |
| 1926 | ||
| 1927 | ObligationCause::new(self.span, CRATE_DEF_ID, cause_code.clone()) | |
| 1928 | } | |
| 1929 | } |
compiler/rustc_codegen_llvm/src/back/lto.rs+3-1| ... | ... | @@ -620,7 +620,9 @@ pub(crate) fn run_pass_manager( |
| 620 | 620 | if cfg!(feature = "llvm_enzyme") && enable_ad && !thin { |
| 621 | 621 | let opt_stage = llvm::OptStage::FatLTO; |
| 622 | 622 | let stage = write::AutodiffStage::PostAD; |
| 623 | if !config.autodiff.contains(&config::AutoDiff::NoPostopt) { | |
| 623 | if !config.autodiff.contains(&config::AutoDiff::NoPostopt) | |
| 624 | && config.autodiff_post_passes.as_deref() != Some("") | |
| 625 | { | |
| 624 | 626 | unsafe { |
| 625 | 627 | write::llvm_optimize( |
| 626 | 628 | cgcx, prof, dcx, module, None, None, config, opt_level, opt_stage, stage, |
compiler/rustc_codegen_llvm/src/back/write.rs+10| ... | ... | @@ -566,6 +566,14 @@ pub(crate) unsafe fn llvm_optimize( |
| 566 | 566 | let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore); |
| 567 | 567 | let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter); |
| 568 | 568 | let print_passes = config.autodiff.contains(&config::AutoDiff::PrintPasses); |
| 569 | let passes_after_enzyme = if autodiff_stage == AutodiffStage::PostAD { | |
| 570 | config.autodiff_post_passes.as_deref() | |
| 571 | } else { | |
| 572 | None | |
| 573 | }; | |
| 574 | let passes_after_enzyme_ptr = | |
| 575 | passes_after_enzyme.map_or(std::ptr::null(), |s| s.as_c_char_ptr()); | |
| 576 | let passes_after_enzyme_len = passes_after_enzyme.map_or(0, |s| s.len()); | |
| 569 | 577 | let merge_functions; |
| 570 | 578 | let unroll_loops; |
| 571 | 579 | let vectorize_slp; |
| ... | ... | @@ -795,6 +803,8 @@ pub(crate) unsafe fn llvm_optimize( |
| 795 | 803 | llvm_selfprofiler, |
| 796 | 804 | selfprofile_before_pass_callback, |
| 797 | 805 | selfprofile_after_pass_callback, |
| 806 | passes_after_enzyme_ptr, | |
| 807 | passes_after_enzyme_len, | |
| 798 | 808 | extra_passes.as_c_char_ptr(), |
| 799 | 809 | extra_passes.len(), |
| 800 | 810 | llvm_plugins.as_c_char_ptr(), |
compiler/rustc_codegen_llvm/src/llvm/ffi.rs+2| ... | ... | @@ -2492,6 +2492,8 @@ unsafe extern "C" { |
| 2492 | 2492 | llvm_selfprofiler: *mut c_void, |
| 2493 | 2493 | begin_callback: SelfProfileBeforePassCallback, |
| 2494 | 2494 | end_callback: SelfProfileAfterPassCallback, |
| 2495 | PostEnzymePasses: *const c_char, | |
| 2496 | PostEnzymePassesLen: size_t, | |
| 2495 | 2497 | ExtraPasses: *const c_char, |
| 2496 | 2498 | ExtraPassesLen: size_t, |
| 2497 | 2499 | LLVMPlugins: *const c_char, |
compiler/rustc_codegen_ssa/src/back/write.rs+5| ... | ... | @@ -106,6 +106,7 @@ pub struct ModuleConfig { |
| 106 | 106 | pub emit_lifetime_markers: bool, |
| 107 | 107 | pub llvm_plugins: Vec<String>, |
| 108 | 108 | pub autodiff: Vec<config::AutoDiff>, |
| 109 | pub autodiff_post_passes: Option<String>, | |
| 109 | 110 | pub offload: Vec<config::Offload>, |
| 110 | 111 | } |
| 111 | 112 | |
| ... | ... | @@ -257,6 +258,10 @@ impl ModuleConfig { |
| 257 | 258 | emit_lifetime_markers: sess.emit_lifetime_markers(), |
| 258 | 259 | llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]), |
| 259 | 260 | autodiff: if_regular!(sess.opts.unstable_opts.autodiff.clone(), vec![]), |
| 261 | autodiff_post_passes: if_regular!( | |
| 262 | sess.opts.unstable_opts.autodiff_post_passes.clone(), | |
| 263 | None | |
| 264 | ), | |
| 260 | 265 | offload: if_regular!(sess.opts.unstable_opts.offload.clone(), vec![]), |
| 261 | 266 | } |
| 262 | 267 | } |
compiler/rustc_const_eval/src/interpret/step.rs+3-2| ... | ... | @@ -552,16 +552,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |
| 552 | 552 | let old_stack = self.frame_idx(); |
| 553 | 553 | let old_loc = self.frame().loc; |
| 554 | 554 | |
| 555 | // Evaluation order consistent with assignment: destination first. | |
| 556 | let dest_place = self.eval_place(destination)?; | |
| 555 | 557 | let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } = |
| 556 | 558 | self.eval_callee_and_args(terminator, func, args, &destination)?; |
| 557 | 559 | |
| 558 | let destination = self.eval_place(destination)?; | |
| 559 | 560 | self.init_fn_call( |
| 560 | 561 | callee, |
| 561 | 562 | (fn_sig.abi(), fn_abi), |
| 562 | 563 | &args, |
| 563 | 564 | with_caller_location, |
| 564 | &destination, | |
| 565 | &dest_place, | |
| 565 | 566 | target, |
| 566 | 567 | if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable }, |
| 567 | 568 | )?; |
compiler/rustc_expand/src/expand.rs+2-38| ... | ... | @@ -5,7 +5,7 @@ use std::{iter, mem, slice}; |
| 5 | 5 | |
| 6 | 6 | use rustc_ast::mut_visit::*; |
| 7 | 7 | use rustc_ast::tokenstream::TokenStream; |
| 8 | use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; | |
| 8 | use rustc_ast::visit::{AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; | |
| 9 | 9 | use rustc_ast::{ |
| 10 | 10 | self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, |
| 11 | 11 | DUMMY_NODE_ID, DelegationSource, DelegationSuffixes, EarlyParsedAttribute, ExprKind, |
| ... | ... | @@ -20,7 +20,7 @@ use rustc_attr_parsing::{ |
| 20 | 20 | }; |
| 21 | 21 | use rustc_data_structures::flat_map_in_place::FlatMapInPlace; |
| 22 | 22 | use rustc_data_structures::stack::ensure_sufficient_stack; |
| 23 | use rustc_errors::{PResult, msg}; | |
| 23 | use rustc_errors::PResult; | |
| 24 | 24 | use rustc_feature::Features; |
| 25 | 25 | use rustc_hir::Target; |
| 26 | 26 | use rustc_hir::def::MacroKinds; |
| ... | ... | @@ -29,7 +29,6 @@ use rustc_parse::parser::{ |
| 29 | 29 | AllowConstBlockItems, AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, |
| 30 | 30 | RecoverColon, RecoverComma, Recovery, token_descr, |
| 31 | 31 | }; |
| 32 | use rustc_session::Session; | |
| 33 | 32 | use rustc_session::errors::feature_err; |
| 34 | 33 | use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; |
| 35 | 34 | use rustc_span::hygiene::SyntaxContext; |
| ... | ... | @@ -770,7 +769,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { |
| 770 | 769 | } |
| 771 | 770 | InvocationKind::Attr { attr, pos, mut item, derives } => { |
| 772 | 771 | if let Some(expander) = ext.as_attr() { |
| 773 | self.gate_proc_macro_input(&item); | |
| 774 | 772 | self.gate_proc_macro_attr_item(span, &item); |
| 775 | 773 | let tokens = match &item { |
| 776 | 774 | // FIXME: Collect tokens and use them instead of generating |
| ... | ... | @@ -904,9 +902,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { |
| 904 | 902 | InvocationKind::Derive { path, item, is_const } => match ext { |
| 905 | 903 | SyntaxExtensionKind::Derive(expander) |
| 906 | 904 | | SyntaxExtensionKind::LegacyDerive(expander) => { |
| 907 | if let SyntaxExtensionKind::Derive(..) = ext { | |
| 908 | self.gate_proc_macro_input(&item); | |
| 909 | } | |
| 910 | 905 | // The `MetaItem` representing the trait to derive can't |
| 911 | 906 | // have an unsafe around it (as of now). |
| 912 | 907 | let meta = ast::MetaItem { |
| ... | ... | @@ -1043,37 +1038,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { |
| 1043 | 1038 | .emit(); |
| 1044 | 1039 | } |
| 1045 | 1040 | |
| 1046 | fn gate_proc_macro_input(&self, annotatable: &Annotatable) { | |
| 1047 | struct GateProcMacroInput<'a> { | |
| 1048 | sess: &'a Session, | |
| 1049 | } | |
| 1050 | ||
| 1051 | impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> { | |
| 1052 | fn visit_item(&mut self, item: &'ast ast::Item) { | |
| 1053 | match &item.kind { | |
| 1054 | ItemKind::Mod(_, _, mod_kind) | |
| 1055 | if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) => | |
| 1056 | { | |
| 1057 | feature_err( | |
| 1058 | self.sess, | |
| 1059 | sym::proc_macro_hygiene, | |
| 1060 | item.span, | |
| 1061 | msg!("file modules in proc macro input are unstable"), | |
| 1062 | ) | |
| 1063 | .emit(); | |
| 1064 | } | |
| 1065 | _ => {} | |
| 1066 | } | |
| 1067 | ||
| 1068 | visit::walk_item(self, item); | |
| 1069 | } | |
| 1070 | } | |
| 1071 | ||
| 1072 | if !self.cx.ecfg.features.proc_macro_hygiene() { | |
| 1073 | annotatable.visit_with(&mut GateProcMacroInput { sess: self.cx.sess }); | |
| 1074 | } | |
| 1075 | } | |
| 1076 | ||
| 1077 | 1041 | fn parse_ast_fragment( |
| 1078 | 1042 | &mut self, |
| 1079 | 1043 | toks: TokenStream, |
compiler/rustc_feature/src/unstable.rs+1-1| ... | ... | @@ -696,7 +696,7 @@ declare_features! ( |
| 696 | 696 | (unstable, powerpc_target_feature, "1.27.0", Some(150255)), |
| 697 | 697 | /// The prfchw target feature on x86. |
| 698 | 698 | (unstable, prfchw_target_feature, "1.78.0", Some(150256)), |
| 699 | /// Allows macro attributes on expressions, statements and non-inline modules. | |
| 699 | /// Allows macro attributes on expressions and statements. | |
| 700 | 700 | (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), |
| 701 | 701 | /// Allows the use of raw-dylibs on ELF platforms |
| 702 | 702 | (incomplete, raw_dylib_elf, "1.87.0", Some(135694)), |
compiler/rustc_hir_analysis/src/coherence/builtin.rs+47-49| ... | ... | @@ -10,7 +10,7 @@ use rustc_hir::ItemKind; |
| 10 | 10 | use rustc_hir::def_id::{DefId, LocalDefId}; |
| 11 | 11 | use rustc_hir::lang_items::LangItem; |
| 12 | 12 | use rustc_infer::infer::{self, InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt}; |
| 13 | use rustc_infer::traits::{Obligation, PredicateObligations}; | |
| 13 | use rustc_infer::traits::Obligation; | |
| 14 | 14 | use rustc_middle::ty::adjustment::CoerceUnsizedInfo; |
| 15 | 15 | use rustc_middle::ty::print::PrintTraitRefExt as _; |
| 16 | 16 | use rustc_middle::ty::relate::solver_relating::RelateExt; |
| ... | ... | @@ -469,37 +469,6 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() |
| 469 | 469 | } |
| 470 | 470 | } |
| 471 | 471 | |
| 472 | fn structurally_normalize_ty<'tcx>( | |
| 473 | tcx: TyCtxt<'tcx>, | |
| 474 | infcx: &InferCtxt<'tcx>, | |
| 475 | impl_did: LocalDefId, | |
| 476 | span: Span, | |
| 477 | ty: Unnormalized<'tcx, Ty<'tcx>>, | |
| 478 | ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> { | |
| 479 | let ocx = ObligationCtxt::new(infcx); | |
| 480 | let Ok(normalized_ty) = ocx.structurally_normalize_ty( | |
| 481 | &traits::ObligationCause::misc(span, impl_did), | |
| 482 | tcx.param_env(impl_did), | |
| 483 | ty, | |
| 484 | ) else { | |
| 485 | // We shouldn't have errors here in the old solver, except for | |
| 486 | // evaluate/fulfill mismatches, but that's not a reason for an ICE. | |
| 487 | return None; | |
| 488 | }; | |
| 489 | let errors = ocx.try_evaluate_obligations(); | |
| 490 | if !errors.is_empty() { | |
| 491 | if infcx.next_trait_solver() { | |
| 492 | unreachable!(); | |
| 493 | } | |
| 494 | // We shouldn't have errors here in the old solver, except for | |
| 495 | // evaluate/fulfill mismatches, but that's not a reason for an ICE. | |
| 496 | debug!(?errors, "encountered errors while fulfilling"); | |
| 497 | return None; | |
| 498 | } | |
| 499 | ||
| 500 | Some((normalized_ty, ocx.into_pending_obligations())) | |
| 501 | } | |
| 502 | ||
| 503 | 472 | pub(crate) fn reborrow_info<'tcx>( |
| 504 | 473 | tcx: TyCtxt<'tcx>, |
| 505 | 474 | impl_did: LocalDefId, |
| ... | ... | @@ -552,8 +521,12 @@ pub(crate) fn reborrow_info<'tcx>( |
| 552 | 521 | return Ok(()); |
| 553 | 522 | } |
| 554 | 523 | |
| 524 | let ocx = ObligationCtxt::new_with_diagnostics(&infcx); | |
| 555 | 525 | // We've found some data fields. They must all be either be Copy or Reborrow. |
| 556 | 526 | for (field, span) in data_fields { |
| 527 | let field = ocx | |
| 528 | .deeply_normalize(&traits::ObligationCause::misc(span, impl_did), param_env, field) | |
| 529 | .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?; | |
| 557 | 530 | if assert_field_type_is_reborrow( |
| 558 | 531 | tcx, |
| 559 | 532 | &infcx, |
| ... | ... | @@ -620,17 +593,16 @@ pub(crate) fn coerce_shared_info<'tcx>( |
| 620 | 593 | } |
| 621 | 594 | |
| 622 | 595 | assert_eq!(trait_ref.def_id, coerce_shared_trait); |
| 623 | let Some((target, _obligations)) = structurally_normalize_ty( | |
| 624 | tcx, | |
| 625 | &infcx, | |
| 626 | impl_did, | |
| 627 | span, | |
| 628 | Unnormalized::new_wip(trait_ref.args.type_at(1)), | |
| 629 | ) else { | |
| 630 | todo!("something went wrong with structurally_normalize_ty"); | |
| 631 | }; | |
| 632 | ||
| 596 | let ocx = ObligationCtxt::new_with_diagnostics(&infcx); | |
| 633 | 597 | let param_env = tcx.param_env(impl_did); |
| 598 | let (source, target) = ocx | |
| 599 | .deeply_normalize( | |
| 600 | &traits::ObligationCause::misc(span, impl_did), | |
| 601 | param_env, | |
| 602 | Unnormalized::new_wip((source, trait_ref.args.type_at(1))), | |
| 603 | ) | |
| 604 | .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?; | |
| 605 | ||
| 634 | 606 | assert!(!source.has_escaping_bound_vars()); |
| 635 | 607 | |
| 636 | 608 | let data = match (source.kind(), target.kind()) { |
| ... | ... | @@ -672,6 +644,20 @@ pub(crate) fn coerce_shared_info<'tcx>( |
| 672 | 644 | // them below. |
| 673 | 645 | let (a, span_a) = a_data_fields[0]; |
| 674 | 646 | let (b, span_b) = b_data_fields[0]; |
| 647 | let a = ocx | |
| 648 | .deeply_normalize( | |
| 649 | &traits::ObligationCause::misc(span_a, impl_did), | |
| 650 | param_env, | |
| 651 | a, | |
| 652 | ) | |
| 653 | .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?; | |
| 654 | let b = ocx | |
| 655 | .deeply_normalize( | |
| 656 | &traits::ObligationCause::misc(span_b, impl_did), | |
| 657 | param_env, | |
| 658 | b, | |
| 659 | ) | |
| 660 | .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?; | |
| 675 | 661 | |
| 676 | 662 | Some((a, b, coerce_shared_trait, span_a, span_b)) |
| 677 | 663 | } else { |
| ... | ... | @@ -696,12 +682,19 @@ pub(crate) fn coerce_shared_info<'tcx>( |
| 696 | 682 | // |
| 697 | 683 | // 1 data field each; they must be the same type and Copy, or relate to one another using |
| 698 | 684 | // CoerceShared. |
| 685 | // | |
| 686 | // FIXME(reborrow): we should do the relating inside `probe` so the region constraint | |
| 687 | // doesn't affect later result in case that this relating fails. | |
| 688 | // We should resolve regions if the relating succeeds. | |
| 689 | // Besides, the regions of `Ref`s are not checked here so `&'a mut T -> &'static T` is | |
| 690 | // allowed. | |
| 699 | 691 | if source.ref_mutability() == Some(ty::Mutability::Mut) |
| 700 | 692 | && target.ref_mutability() == Some(ty::Mutability::Not) |
| 701 | 693 | && infcx |
| 702 | .eq_structurally_relating_aliases( | |
| 694 | .relate( | |
| 703 | 695 | param_env, |
| 704 | 696 | source.peel_refs(), |
| 697 | ty::Variance::Invariant, | |
| 705 | 698 | target.peel_refs(), |
| 706 | 699 | source_field_span, |
| 707 | 700 | ) |
| ... | ... | @@ -710,14 +703,16 @@ pub(crate) fn coerce_shared_info<'tcx>( |
| 710 | 703 | // &mut T implements CoerceShared to &T, except not really. |
| 711 | 704 | return Ok(()); |
| 712 | 705 | } |
| 706 | ||
| 707 | // FIXME(reborrow): we should do the relating inside `probe` so the region constraint | |
| 708 | // doesn't affect later result in case that this relating fails. | |
| 713 | 709 | if infcx |
| 714 | .eq_structurally_relating_aliases(param_env, source, target, source_field_span) | |
| 710 | .relate(param_env, source, ty::Variance::Invariant, target, source_field_span) | |
| 715 | 711 | .is_err() |
| 716 | 712 | { |
| 717 | 713 | // The two data fields don't agree on a common type; this means |
| 718 | 714 | // that they must be `A: CoerceShared<B>`. Register an obligation |
| 719 | 715 | // for that. |
| 720 | let ocx = ObligationCtxt::new_with_diagnostics(&infcx); | |
| 721 | 716 | let cause = traits::ObligationCause::misc(span, impl_did); |
| 722 | 717 | let obligation = Obligation::new( |
| 723 | 718 | tcx, |
| ... | ... | @@ -735,6 +730,8 @@ pub(crate) fn coerce_shared_info<'tcx>( |
| 735 | 730 | ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?; |
| 736 | 731 | } else { |
| 737 | 732 | // Types match: check that it is Copy. |
| 733 | // | |
| 734 | // FIXME(reborrow): We should resolve regions here. | |
| 738 | 735 | assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, source, source_field_span)?; |
| 739 | 736 | } |
| 740 | 737 | } |
| ... | ... | @@ -754,19 +751,20 @@ fn generic_lifetime_params_count(args: &[ty::GenericArg<'_>]) -> usize { |
| 754 | 751 | args.iter().filter(|arg| arg.as_region().is_some()).count() |
| 755 | 752 | } |
| 756 | 753 | |
| 757 | // FIXME(#155345): This should return `Unnormalized` | |
| 758 | 754 | fn collect_struct_data_fields<'tcx>( |
| 759 | 755 | tcx: TyCtxt<'tcx>, |
| 760 | 756 | def: ty::AdtDef<'tcx>, |
| 761 | 757 | args: ty::GenericArgsRef<'tcx>, |
| 762 | ) -> Vec<(Ty<'tcx>, Span)> { | |
| 758 | ) -> Vec<(Unnormalized<'tcx, Ty<'tcx>>, Span)> { | |
| 763 | 759 | def.non_enum_variant() |
| 764 | 760 | .fields |
| 765 | 761 | .iter() |
| 766 | 762 | .filter_map(|f| { |
| 767 | 763 | // Ignore PhantomData fields |
| 768 | let ty = f.ty(tcx, args).skip_norm_wip(); | |
| 769 | if ty.is_phantom_data() { | |
| 764 | let ty = f.ty(tcx, args); | |
| 765 | // FIXME(#155345): alias might be normalized to PhantomData. | |
| 766 | // We probably should normalize here instead. | |
| 767 | if ty.skip_norm_wip().is_phantom_data() { | |
| 770 | 768 | return None; |
| 771 | 769 | } |
| 772 | 770 | Some((ty, tcx.def_span(f.did))) |
compiler/rustc_hir_analysis/src/coherence/orphan.rs+7-1| ... | ... | @@ -97,7 +97,13 @@ pub(crate) fn orphan_check_impl( |
| 97 | 97 | ); |
| 98 | 98 | |
| 99 | 99 | if tcx.trait_is_auto(trait_def_id) { |
| 100 | let self_ty = trait_ref.self_ty(); | |
| 100 | // Expand free alias types (e.g. lazy type aliases) so that the checks below operate | |
| 101 | // on the type the alias resolves to rather than the alias itself. Otherwise an impl | |
| 102 | // whose self type is an alias expanding to an otherwise valid nominal type would be | |
| 103 | // wrongly rejected, e.g. `unsafe impl Sync for Alias {}` where `type Alias = Local;`. | |
| 104 | // Expansion also reveals genuinely problematic self types (trait objects, opaque | |
| 105 | // types, type parameters), so those keep being rejected. See issue #157756. | |
| 106 | let self_ty = tcx.expand_free_alias_tys(trait_ref.self_ty()); | |
| 101 | 107 | |
| 102 | 108 | // If the impl is in the same crate as the auto-trait, almost anything |
| 103 | 109 | // goes. |
compiler/rustc_interface/src/tests.rs+1| ... | ... | @@ -788,6 +788,7 @@ fn test_unstable_options_tracking_hash() { |
| 788 | 788 | tracked!(annotate_moves, AnnotateMoves::Enabled(Some(1234))); |
| 789 | 789 | tracked!(assume_incomplete_release, true); |
| 790 | 790 | tracked!(autodiff, vec![AutoDiff::Enable, AutoDiff::NoTT]); |
| 791 | tracked!(autodiff_post_passes, Some("function(mem2reg,instsimplify,simplifycfg)".to_string())); | |
| 791 | 792 | tracked!(binary_dep_depinfo, true); |
| 792 | 793 | tracked!(box_noalias, false); |
| 793 | 794 | tracked!( |
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp+113-102| ... | ... | @@ -616,6 +616,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( |
| 616 | 616 | bool DebugInfoForProfiling, void *LlvmSelfProfiler, |
| 617 | 617 | LLVMRustSelfProfileBeforePassCallback BeforePassCallback, |
| 618 | 618 | LLVMRustSelfProfileAfterPassCallback AfterPassCallback, |
| 619 | const char *PostEnzymePasses, size_t PostEnzymePassesLen, | |
| 619 | 620 | const char *ExtraPasses, size_t ExtraPassesLen, const char *LLVMPlugins, |
| 620 | 621 | size_t LLVMPluginsLen) { |
| 621 | 622 | Module *TheModule = unwrap(ModuleRef); |
| ... | ... | @@ -852,120 +853,130 @@ extern "C" LLVMRustResult LLVMRustOptimize( |
| 852 | 853 | raw_string_ostream ThinLinkDataOS(ThinLTOSummaryBuffer->data); |
| 853 | 854 | bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || |
| 854 | 855 | OptStage == LLVMRustOptStage::FatLTO; |
| 855 | if (!NoPrepopulatePasses) { | |
| 856 | for (const auto &C : PipelineStartEPCallbacks) | |
| 857 | PB.registerPipelineStartEPCallback(C); | |
| 858 | for (const auto &C : OptimizerLastEPCallbacks) | |
| 859 | PB.registerOptimizerLastEPCallback(C); | |
| 860 | ||
| 861 | // The pre-link pipelines don't support O0 and require using | |
| 862 | // buildO0DefaultPipeline() instead. At the same time, the LTO pipelines do | |
| 863 | // support O0 and using them is required. | |
| 864 | if (OptLevel == OptimizationLevel::O0 && !IsLTO) { | |
| 865 | // We manually schedule ThinLTOBufferPasses below, so don't pass the value | |
| 866 | // to enable it here. | |
| 867 | MPM = PB.buildO0DefaultPipeline(OptLevel); | |
| 868 | } else { | |
| 869 | switch (OptStage) { | |
| 870 | case LLVMRustOptStage::PreLinkNoLTO: | |
| 871 | if (ThinLTOBufferRef) { | |
| 872 | // This is similar to LLVM's `buildFatLTODefaultPipeline`, where the | |
| 873 | // bitcode for embedding is obtained after performing | |
| 874 | // `ThinLTOPreLinkDefaultPipeline`. | |
| 875 | MPM.addPass(PB.buildThinLTOPreLinkDefaultPipeline(OptLevel)); | |
| 876 | MPM.addPass(ThinLTOBitcodeWriterPass( | |
| 877 | ThinLTODataOS, | |
| 878 | ThinLTOSummaryBufferRef ? &ThinLinkDataOS : nullptr)); | |
| 879 | *ThinLTOBufferRef = ThinLTOBuffer.release(); | |
| 880 | if (ThinLTOSummaryBufferRef) { | |
| 881 | *ThinLTOSummaryBufferRef = ThinLTOSummaryBuffer.release(); | |
| 856 | if (PostEnzymePassesLen) { | |
| 857 | if (auto Err = PB.parsePassPipeline( | |
| 858 | MPM, StringRef(PostEnzymePasses, PostEnzymePassesLen))) { | |
| 859 | std::string ErrMsg = toString(std::move(Err)); | |
| 860 | LLVMRustSetLastError(ErrMsg.c_str()); | |
| 861 | return LLVMRustResult::Failure; | |
| 862 | } | |
| 863 | } else { | |
| 864 | if (!NoPrepopulatePasses) { | |
| 865 | for (const auto &C : PipelineStartEPCallbacks) | |
| 866 | PB.registerPipelineStartEPCallback(C); | |
| 867 | for (const auto &C : OptimizerLastEPCallbacks) | |
| 868 | PB.registerOptimizerLastEPCallback(C); | |
| 869 | ||
| 870 | // The pre-link pipelines don't support O0 and require using | |
| 871 | // buildO0DefaultPipeline() instead. At the same time, the LTO pipelines | |
| 872 | // do support O0 and using them is required. | |
| 873 | if (OptLevel == OptimizationLevel::O0 && !IsLTO) { | |
| 874 | // We manually schedule ThinLTOBufferPasses below, so don't pass the | |
| 875 | // value to enable it here. | |
| 876 | MPM = PB.buildO0DefaultPipeline(OptLevel); | |
| 877 | } else { | |
| 878 | switch (OptStage) { | |
| 879 | case LLVMRustOptStage::PreLinkNoLTO: | |
| 880 | if (ThinLTOBufferRef) { | |
| 881 | // This is similar to LLVM's `buildFatLTODefaultPipeline`, where the | |
| 882 | // bitcode for embedding is obtained after performing | |
| 883 | // `ThinLTOPreLinkDefaultPipeline`. | |
| 884 | MPM.addPass(PB.buildThinLTOPreLinkDefaultPipeline(OptLevel)); | |
| 885 | MPM.addPass(ThinLTOBitcodeWriterPass( | |
| 886 | ThinLTODataOS, | |
| 887 | ThinLTOSummaryBufferRef ? &ThinLinkDataOS : nullptr)); | |
| 888 | *ThinLTOBufferRef = ThinLTOBuffer.release(); | |
| 889 | if (ThinLTOSummaryBufferRef) { | |
| 890 | *ThinLTOSummaryBufferRef = ThinLTOSummaryBuffer.release(); | |
| 891 | } | |
| 892 | MPM.addPass(PB.buildModuleOptimizationPipeline( | |
| 893 | OptLevel, ThinOrFullLTOPhase::None)); | |
| 894 | MPM.addPass( | |
| 895 | createModuleToFunctionPassAdaptor(AnnotationRemarksPass())); | |
| 896 | } else { | |
| 897 | MPM = PB.buildPerModuleDefaultPipeline(OptLevel); | |
| 882 | 898 | } |
| 883 | MPM.addPass(PB.buildModuleOptimizationPipeline( | |
| 884 | OptLevel, ThinOrFullLTOPhase::None)); | |
| 885 | MPM.addPass( | |
| 886 | createModuleToFunctionPassAdaptor(AnnotationRemarksPass())); | |
| 887 | } else { | |
| 888 | MPM = PB.buildPerModuleDefaultPipeline(OptLevel); | |
| 899 | break; | |
| 900 | case LLVMRustOptStage::PreLinkThinLTO: | |
| 901 | case LLVMRustOptStage::PreLinkFatLTO: | |
| 902 | MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel); | |
| 903 | NeedThinLTOBufferPasses = false; | |
| 904 | break; | |
| 905 | case LLVMRustOptStage::ThinLTO: | |
| 906 | // FIXME: Does it make sense to pass the ModuleSummaryIndex? | |
| 907 | // It only seems to be needed for C++ specific optimizations. | |
| 908 | MPM = PB.buildThinLTODefaultPipeline(OptLevel, nullptr); | |
| 909 | break; | |
| 910 | case LLVMRustOptStage::FatLTO: | |
| 911 | MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr); | |
| 912 | NeedThinLTOBufferPasses = false; | |
| 913 | break; | |
| 889 | 914 | } |
| 890 | break; | |
| 891 | case LLVMRustOptStage::PreLinkThinLTO: | |
| 892 | case LLVMRustOptStage::PreLinkFatLTO: | |
| 893 | MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel); | |
| 894 | NeedThinLTOBufferPasses = false; | |
| 895 | break; | |
| 896 | case LLVMRustOptStage::ThinLTO: | |
| 897 | // FIXME: Does it make sense to pass the ModuleSummaryIndex? | |
| 898 | // It only seems to be needed for C++ specific optimizations. | |
| 899 | MPM = PB.buildThinLTODefaultPipeline(OptLevel, nullptr); | |
| 900 | break; | |
| 901 | case LLVMRustOptStage::FatLTO: | |
| 902 | MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr); | |
| 903 | NeedThinLTOBufferPasses = false; | |
| 904 | break; | |
| 905 | 915 | } |
| 916 | } else { | |
| 917 | // We're not building any of the default pipelines but we still want to | |
| 918 | // add the verifier, instrumentation, etc passes if they were requested | |
| 919 | for (const auto &C : PipelineStartEPCallbacks) | |
| 920 | C(MPM, OptLevel); | |
| 921 | for (const auto &C : OptimizerLastEPCallbacks) | |
| 922 | C(MPM, OptLevel, ThinOrFullLTOPhase::None); | |
| 906 | 923 | } |
| 907 | } else { | |
| 908 | // We're not building any of the default pipelines but we still want to | |
| 909 | // add the verifier, instrumentation, etc passes if they were requested | |
| 910 | for (const auto &C : PipelineStartEPCallbacks) | |
| 911 | C(MPM, OptLevel); | |
| 912 | for (const auto &C : OptimizerLastEPCallbacks) | |
| 913 | C(MPM, OptLevel, ThinOrFullLTOPhase::None); | |
| 914 | } | |
| 915 | 924 | |
| 916 | if (ExtraPassesLen) { | |
| 917 | if (auto Err = | |
| 918 | PB.parsePassPipeline(MPM, StringRef(ExtraPasses, ExtraPassesLen))) { | |
| 919 | std::string ErrMsg = toString(std::move(Err)); | |
| 920 | LLVMRustSetLastError(ErrMsg.c_str()); | |
| 921 | return LLVMRustResult::Failure; | |
| 925 | if (ExtraPassesLen) { | |
| 926 | if (auto Err = PB.parsePassPipeline( | |
| 927 | MPM, StringRef(ExtraPasses, ExtraPassesLen))) { | |
| 928 | std::string ErrMsg = toString(std::move(Err)); | |
| 929 | LLVMRustSetLastError(ErrMsg.c_str()); | |
| 930 | return LLVMRustResult::Failure; | |
| 931 | } | |
| 922 | 932 | } |
| 923 | } | |
| 924 | 933 | |
| 925 | if (NeedThinLTOBufferPasses) { | |
| 926 | MPM.addPass(CanonicalizeAliasesPass()); | |
| 927 | MPM.addPass(NameAnonGlobalPass()); | |
| 928 | } | |
| 929 | // For `-Copt-level=0`, and the pre-link fat/thin LTO stages. | |
| 930 | if (ThinLTOBufferRef && *ThinLTOBufferRef == nullptr) { | |
| 931 | // thin lto summaries prevent fat lto, so do not emit them if fat | |
| 932 | // lto is requested. See PR #136840 for background information. | |
| 933 | if (OptStage != LLVMRustOptStage::PreLinkFatLTO) { | |
| 934 | MPM.addPass(ThinLTOBitcodeWriterPass( | |
| 935 | ThinLTODataOS, ThinLTOSummaryBufferRef ? &ThinLinkDataOS : nullptr)); | |
| 936 | } else { | |
| 937 | MPM.addPass(BitcodeWriterPass(ThinLTODataOS)); | |
| 934 | if (NeedThinLTOBufferPasses) { | |
| 935 | MPM.addPass(CanonicalizeAliasesPass()); | |
| 936 | MPM.addPass(NameAnonGlobalPass()); | |
| 938 | 937 | } |
| 939 | *ThinLTOBufferRef = ThinLTOBuffer.release(); | |
| 940 | if (ThinLTOSummaryBufferRef) { | |
| 941 | *ThinLTOSummaryBufferRef = ThinLTOSummaryBuffer.release(); | |
| 938 | // For `-Copt-level=0`, and the pre-link fat/thin LTO stages. | |
| 939 | if (ThinLTOBufferRef && *ThinLTOBufferRef == nullptr) { | |
| 940 | // thin lto summaries prevent fat lto, so do not emit them if fat | |
| 941 | // lto is requested. See PR #136840 for background information. | |
| 942 | if (OptStage != LLVMRustOptStage::PreLinkFatLTO) { | |
| 943 | MPM.addPass(ThinLTOBitcodeWriterPass( | |
| 944 | ThinLTODataOS, | |
| 945 | ThinLTOSummaryBufferRef ? &ThinLinkDataOS : nullptr)); | |
| 946 | } else { | |
| 947 | MPM.addPass(BitcodeWriterPass(ThinLTODataOS)); | |
| 948 | } | |
| 949 | *ThinLTOBufferRef = ThinLTOBuffer.release(); | |
| 950 | if (ThinLTOSummaryBufferRef) { | |
| 951 | *ThinLTOSummaryBufferRef = ThinLTOSummaryBuffer.release(); | |
| 952 | } | |
| 942 | 953 | } |
| 943 | } | |
| 944 | 954 | |
| 945 | // now load "-enzyme" pass: | |
| 946 | // With dlopen, ENZYME macro may not be defined, so check EnzymePtr directly | |
| 947 | // In the case of debug builds with multiple codegen units, we might not | |
| 948 | // have all function definitions available during the early compiler | |
| 949 | // invocations. We therefore wait for the final lto step to run Enzyme. | |
| 950 | if (EnzymePtr && IsLTO) { | |
| 951 | ||
| 952 | if (PrintBeforeEnzyme) { | |
| 953 | // Handle the Rust flag `-Zautodiff=PrintModBefore`. | |
| 954 | std::string Banner = "Module before EnzymeNewPM"; | |
| 955 | MPM.addPass(PrintModulePass(outs(), Banner, true, false)); | |
| 956 | } | |
| 955 | // now load "-enzyme" pass: | |
| 956 | // With dlopen, ENZYME macro may not be defined, so check EnzymePtr directly | |
| 957 | // In the case of debug builds with multiple codegen units, we might not | |
| 958 | // have all function definitions available during the early compiler | |
| 959 | // invocations. We therefore wait for the final lto step to run Enzyme. | |
| 960 | if (EnzymePtr && IsLTO) { | |
| 961 | ||
| 962 | if (PrintBeforeEnzyme) { | |
| 963 | // Handle the Rust flag `-Zautodiff=PrintModBefore`. | |
| 964 | std::string Banner = "Module before EnzymeNewPM"; | |
| 965 | MPM.addPass(PrintModulePass(outs(), Banner, true, false)); | |
| 966 | } | |
| 957 | 967 | |
| 958 | EnzymePtr(PB, false); | |
| 959 | if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) { | |
| 960 | std::string ErrMsg = toString(std::move(Err)); | |
| 961 | LLVMRustSetLastError(ErrMsg.c_str()); | |
| 962 | return LLVMRustResult::Failure; | |
| 963 | } | |
| 968 | EnzymePtr(PB, false); | |
| 969 | if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) { | |
| 970 | std::string ErrMsg = toString(std::move(Err)); | |
| 971 | LLVMRustSetLastError(ErrMsg.c_str()); | |
| 972 | return LLVMRustResult::Failure; | |
| 973 | } | |
| 964 | 974 | |
| 965 | if (PrintAfterEnzyme) { | |
| 966 | // Handle the Rust flag `-Zautodiff=PrintModAfter`. | |
| 967 | std::string Banner = "Module after EnzymeNewPM"; | |
| 968 | MPM.addPass(PrintModulePass(outs(), Banner, true, false)); | |
| 975 | if (PrintAfterEnzyme) { | |
| 976 | // Handle the Rust flag `-Zautodiff=PrintModAfter`. | |
| 977 | std::string Banner = "Module after EnzymeNewPM"; | |
| 978 | MPM.addPass(PrintModulePass(outs(), Banner, true, false)); | |
| 979 | } | |
| 969 | 980 | } |
| 970 | 981 | } |
| 971 | 982 |
compiler/rustc_middle/src/mir/syntax.rs+7-4| ... | ... | @@ -306,9 +306,9 @@ pub enum StatementKind<'tcx> { |
| 306 | 306 | /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except |
| 307 | 307 | /// without the possibility of dropping the previous value (that must be done separately, if at |
| 308 | 308 | /// all). The *exact* way this works is undecided. It probably does something like evaluating |
| 309 | /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various | |
| 310 | /// parts of this may do type specific things that are more complicated than simply copying | |
| 311 | /// bytes. In particular, the assignment will typically erase the contents of padding, | |
| 309 | /// the LHS to a place, then the RHS to a value, and then storing the value to the place. | |
| 310 | /// Various parts of this may do type specific things that are more complicated than simply | |
| 311 | /// copying bytes. In particular, the assignment will typically erase the contents of padding, | |
| 312 | 312 | /// erase provenance from non-pointer types, and implicitly "retag" all references and boxes |
| 313 | 313 | /// that it copies, meaning that the resulting value is not an exact duplicate for all intents |
| 314 | 314 | /// and purposes of the original value. |
| ... | ... | @@ -780,6 +780,9 @@ pub enum TerminatorKind<'tcx> { |
| 780 | 780 | /// operands not aliasing the return place. It is unclear how this is justified in MIR, see |
| 781 | 781 | /// [#71117]. |
| 782 | 782 | /// |
| 783 | /// The evaluation order is currently "first compute destination place, then `func` operand, | |
| 784 | /// then the arguments in left-to-right order". | |
| 785 | /// | |
| 783 | 786 | /// [#71117]: https://github.com/rust-lang/rust/issues/71117 |
| 784 | 787 | Call { |
| 785 | 788 | /// The function that’s being called. |
| ... | ... | @@ -1493,7 +1496,7 @@ pub enum CastKind { |
| 1493 | 1496 | /// but running a transmute between differently-sized types is UB. |
| 1494 | 1497 | Transmute, |
| 1495 | 1498 | |
| 1496 | /// A `Subtype` cast is applied to any `StatementKind::Assign` where | |
| 1499 | /// A `Subtype` cast is applied to any [`StatementKind::Assign`] where | |
| 1497 | 1500 | /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping |
| 1498 | 1501 | /// explicit during optimizations and codegen. |
| 1499 | 1502 | /// |
compiler/rustc_mir_build/src/builder/block.rs+3-3| ... | ... | @@ -184,7 +184,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 184 | 184 | |
| 185 | 185 | // Declare the bindings, which may create a source scope. |
| 186 | 186 | let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree); |
| 187 | this.push_scope((*remainder_scope, source_info)); | |
| 187 | this.push_scope(*remainder_scope); | |
| 188 | 188 | let_scope_stack.push(remainder_scope); |
| 189 | 189 | |
| 190 | 190 | let visibility_scope = |
| ... | ... | @@ -242,7 +242,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 242 | 242 | this.block_context.push(BlockFrame::Statement { ignores_expr_result }); |
| 243 | 243 | |
| 244 | 244 | // Enter the remainder scope, i.e., the bindings' destruction scope. |
| 245 | this.push_scope((*remainder_scope, source_info)); | |
| 245 | this.push_scope(*remainder_scope); | |
| 246 | 246 | let_scope_stack.push(remainder_scope); |
| 247 | 247 | |
| 248 | 248 | // Declare the bindings, which may create a source scope. |
| ... | ... | @@ -346,7 +346,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 346 | 346 | // Finally, we pop all the let scopes before exiting out from the scope of block |
| 347 | 347 | // itself. |
| 348 | 348 | for scope in let_scope_stack.into_iter().rev() { |
| 349 | block = this.pop_scope((*scope, source_info), block).into_block(); | |
| 349 | block = this.pop_scope(*scope, block).into_block(); | |
| 350 | 350 | } |
| 351 | 351 | // Restore the original source scope. |
| 352 | 352 | this.source_scope = outer_source_scope; |
compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs+2-1| ... | ... | @@ -726,7 +726,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 726 | 726 | // This can be `None` if the expression's temporary scope was extended so that it can be |
| 727 | 727 | // borrowed by a `const` or `static`. In that case, it's never dropped. |
| 728 | 728 | if let Some(temp_lifetime) = temp_lifetime { |
| 729 | this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp); | |
| 729 | this.schedule_drop_storage(upvar_span, temp_lifetime, temp); | |
| 730 | this.schedule_drop_value(upvar_span, temp_lifetime, temp); | |
| 730 | 731 | } |
| 731 | 732 | |
| 732 | 733 | block.and(Operand::Move(Place::from(temp))) |
compiler/rustc_mir_build/src/builder/expr/as_temp.rs+3-3| ... | ... | @@ -7,7 +7,7 @@ use rustc_middle::mir::*; |
| 7 | 7 | use rustc_middle::thir::*; |
| 8 | 8 | use tracing::{debug, instrument}; |
| 9 | 9 | |
| 10 | use crate::builder::scope::{DropKind, LintLevel}; | |
| 10 | use crate::builder::scope::LintLevel; | |
| 11 | 11 | use crate::builder::{BlockAnd, BlockAndExtension, Builder}; |
| 12 | 12 | |
| 13 | 13 | impl<'a, 'tcx> Builder<'a, 'tcx> { |
| ... | ... | @@ -120,7 +120,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 120 | 120 | // `bar(&foo())` or anything within a block will keep the |
| 121 | 121 | // regular drops just like runtime code. |
| 122 | 122 | if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { |
| 123 | this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage); | |
| 123 | this.schedule_drop_storage(expr_span, temp_lifetime, temp); | |
| 124 | 124 | } |
| 125 | 125 | } |
| 126 | 126 | } |
| ... | ... | @@ -128,7 +128,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 128 | 128 | block = this.expr_into_dest(temp_place, block, expr_id).into_block(); |
| 129 | 129 | |
| 130 | 130 | if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { |
| 131 | this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); | |
| 131 | this.schedule_drop_value(expr_span, temp_lifetime, temp); | |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | 134 | if let Some(backwards_incompatible) = temp_lifetime.backwards_incompatible { |
compiler/rustc_mir_build/src/builder/matches/mod.rs+3-3| ... | ... | @@ -28,7 +28,7 @@ use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard}; |
| 28 | 28 | use crate::builder::expr::as_place::PlaceBuilder; |
| 29 | 29 | use crate::builder::matches::buckets::PartitionedCandidates; |
| 30 | 30 | use crate::builder::matches::user_ty::ProjectedUserTypesNode; |
| 31 | use crate::builder::scope::{DropKind, LintLevel}; | |
| 31 | use crate::builder::scope::LintLevel; | |
| 32 | 32 | use crate::builder::{ |
| 33 | 33 | BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, |
| 34 | 34 | }; |
| ... | ... | @@ -791,7 +791,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 791 | 791 | if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) |
| 792 | 792 | && matches!(schedule_drop, ScheduleDrops::Yes) |
| 793 | 793 | { |
| 794 | self.schedule_drop(span, region_scope, local_id, DropKind::Storage); | |
| 794 | self.schedule_drop_storage(span, region_scope, local_id); | |
| 795 | 795 | } |
| 796 | 796 | let local_info = self.local_decls[local_id].local_info.as_mut().unwrap_crate_local(); |
| 797 | 797 | if let LocalInfo::User(BindingForm::Var(var_info)) = &mut **local_info { |
| ... | ... | @@ -808,7 +808,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 808 | 808 | ) { |
| 809 | 809 | let local_id = self.var_local_id(var, for_guard); |
| 810 | 810 | if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) { |
| 811 | self.schedule_drop(span, region_scope, local_id, DropKind::Value); | |
| 811 | self.schedule_drop_value(span, region_scope, local_id); | |
| 812 | 812 | } |
| 813 | 813 | } |
| 814 | 814 |
compiler/rustc_mir_build/src/builder/mod.rs+2-3| ... | ... | @@ -42,7 +42,7 @@ use rustc_middle::{bug, span_bug}; |
| 42 | 42 | use rustc_span::{Span, Symbol}; |
| 43 | 43 | |
| 44 | 44 | use crate::builder::expr::as_place::PlaceBuilder; |
| 45 | use crate::builder::scope::{DropKind, LintLevel}; | |
| 45 | use crate::builder::scope::LintLevel; | |
| 46 | 46 | |
| 47 | 47 | pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( |
| 48 | 48 | tcx: TyCtxt<'tcx>, |
| ... | ... | @@ -955,11 +955,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 955 | 955 | let place = Place::from(local); |
| 956 | 956 | |
| 957 | 957 | // Make sure we drop (parts of) the argument even when not matched on. |
| 958 | self.schedule_drop( | |
| 958 | self.schedule_drop_value( | |
| 959 | 959 | param.pat.as_ref().map_or(expr_span, |pat| pat.span), |
| 960 | 960 | argument_scope, |
| 961 | 961 | local, |
| 962 | DropKind::Value, | |
| 963 | 962 | ); |
| 964 | 963 | |
| 965 | 964 | let Some(ref pat) = param.pat else { |
compiler/rustc_mir_build/src/builder/scope.rs+61-77| ... | ... | @@ -162,7 +162,7 @@ struct DropData { |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | 164 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 165 | pub(crate) enum DropKind { | |
| 165 | enum DropKind { | |
| 166 | 166 | Value, |
| 167 | 167 | Storage, |
| 168 | 168 | ForLint, |
| ... | ... | @@ -488,11 +488,11 @@ impl<'tcx> Scopes<'tcx> { |
| 488 | 488 | } |
| 489 | 489 | } |
| 490 | 490 | |
| 491 | fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) { | |
| 491 | fn push_scope(&mut self, region_scope: region::Scope, vis_scope: SourceScope) { | |
| 492 | 492 | debug!("push_scope({:?})", region_scope); |
| 493 | 493 | self.scopes.push(Scope { |
| 494 | 494 | source_scope: vis_scope, |
| 495 | region_scope: region_scope.0, | |
| 495 | region_scope, | |
| 496 | 496 | drops: vec![], |
| 497 | 497 | moved_locals: vec![], |
| 498 | 498 | cached_unwind_block: None, |
| ... | ... | @@ -500,13 +500,13 @@ impl<'tcx> Scopes<'tcx> { |
| 500 | 500 | }); |
| 501 | 501 | } |
| 502 | 502 | |
| 503 | fn pop_scope(&mut self, region_scope: (region::Scope, SourceInfo)) -> Scope { | |
| 503 | fn pop_scope(&mut self, region_scope: region::Scope) { | |
| 504 | 504 | let scope = self.scopes.pop().unwrap(); |
| 505 | assert_eq!(scope.region_scope, region_scope.0); | |
| 506 | scope | |
| 505 | assert_eq!(scope.region_scope, region_scope); | |
| 507 | 506 | } |
| 508 | 507 | |
| 509 | fn scope_index(&self, region_scope: region::Scope, span: Span) -> usize { | |
| 508 | /// Returns the position in the scope stack of `region_scope`. | |
| 509 | fn stack_index(&self, region_scope: region::Scope, span: Span) -> usize { | |
| 510 | 510 | self.scopes |
| 511 | 511 | .iter() |
| 512 | 512 | .rposition(|scope| scope.region_scope == region_scope) |
| ... | ... | @@ -681,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 681 | 681 | #[instrument(skip(self, f), level = "debug")] |
| 682 | 682 | pub(crate) fn in_scope<F, R>( |
| 683 | 683 | &mut self, |
| 684 | region_scope: (region::Scope, SourceInfo), | |
| 684 | (region_scope, source_info): (region::Scope, SourceInfo), | |
| 685 | 685 | lint_level: LintLevel, |
| 686 | 686 | f: F, |
| 687 | 687 | ) -> BlockAnd<R> |
| ... | ... | @@ -692,7 +692,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 692 | 692 | if let LintLevel::Explicit(current_hir_id) = lint_level { |
| 693 | 693 | let parent_id = |
| 694 | 694 | self.source_scopes[source_scope].local_data.as_ref().unwrap_crate_local().lint_root; |
| 695 | self.maybe_new_source_scope(region_scope.1.span, current_hir_id, parent_id); | |
| 695 | self.maybe_new_source_scope(source_info.span, current_hir_id, parent_id); | |
| 696 | 696 | } |
| 697 | 697 | self.push_scope(region_scope); |
| 698 | 698 | let mut block; |
| ... | ... | @@ -721,7 +721,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 721 | 721 | /// scope and call `pop_scope` afterwards. Note that these two |
| 722 | 722 | /// calls must be paired; using `in_scope` as a convenience |
| 723 | 723 | /// wrapper maybe preferable. |
| 724 | pub(crate) fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) { | |
| 724 | pub(crate) fn push_scope(&mut self, region_scope: region::Scope) { | |
| 725 | 725 | self.scopes.push_scope(region_scope, self.source_scope); |
| 726 | 726 | } |
| 727 | 727 | |
| ... | ... | @@ -730,13 +730,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 730 | 730 | /// This must match 1-to-1 with `push_scope`. |
| 731 | 731 | pub(crate) fn pop_scope( |
| 732 | 732 | &mut self, |
| 733 | region_scope: (region::Scope, SourceInfo), | |
| 733 | region_scope: region::Scope, | |
| 734 | 734 | mut block: BasicBlock, |
| 735 | 735 | ) -> BlockAnd<()> { |
| 736 | 736 | debug!("pop_scope({:?}, {:?})", region_scope, block); |
| 737 | 737 | |
| 738 | 738 | block = self.leave_top_scope(block); |
| 739 | ||
| 740 | 739 | self.scopes.pop_scope(region_scope); |
| 741 | 740 | |
| 742 | 741 | block.unit() |
| ... | ... | @@ -804,7 +803,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 804 | 803 | } |
| 805 | 804 | |
| 806 | 805 | let region_scope = self.scopes.breakable_scopes[break_index].region_scope; |
| 807 | let scope_index = self.scopes.scope_index(region_scope, span); | |
| 806 | let stack_index = self.scopes.stack_index(region_scope, span); | |
| 808 | 807 | let drops = if destination.is_some() { |
| 809 | 808 | &mut self.scopes.breakable_scopes[break_index].break_drops |
| 810 | 809 | } else { |
| ... | ... | @@ -822,7 +821,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 822 | 821 | }; |
| 823 | 822 | |
| 824 | 823 | let mut drop_idx = ROOT_NODE; |
| 825 | for scope in &self.scopes.scopes[scope_index + 1..] { | |
| 824 | for scope in &self.scopes.scopes[stack_index + 1..] { | |
| 826 | 825 | for drop in &scope.drops { |
| 827 | 826 | drop_idx = drops.add_drop(*drop, drop_idx); |
| 828 | 827 | } |
| ... | ... | @@ -1007,9 +1006,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1007 | 1006 | self.block_context.pop(); |
| 1008 | 1007 | |
| 1009 | 1008 | let discr = self.temp(discriminant_ty, source_info.span); |
| 1010 | let scope_index = self | |
| 1009 | let stack_index = self | |
| 1011 | 1010 | .scopes |
| 1012 | .scope_index(self.scopes.const_continuable_scopes[break_index].region_scope, span); | |
| 1011 | .stack_index(self.scopes.const_continuable_scopes[break_index].region_scope, span); | |
| 1013 | 1012 | let scope = &mut self.scopes.const_continuable_scopes[break_index]; |
| 1014 | 1013 | self.cfg.push_assign(block, source_info, discr, rvalue); |
| 1015 | 1014 | let drop_and_continue_block = self.cfg.start_new_block(); |
| ... | ... | @@ -1022,7 +1021,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1022 | 1021 | |
| 1023 | 1022 | let drops = &mut scope.const_continue_drops; |
| 1024 | 1023 | |
| 1025 | let drop_idx = self.scopes.scopes[scope_index + 1..] | |
| 1024 | let drop_idx = self.scopes.scopes[stack_index + 1..] | |
| 1026 | 1025 | .iter() |
| 1027 | 1026 | .flat_map(|scope| &scope.drops) |
| 1028 | 1027 | .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); |
| ... | ... | @@ -1032,10 +1031,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1032 | 1031 | self.cfg.terminate(imaginary_target, source_info, TerminatorKind::UnwindResume); |
| 1033 | 1032 | |
| 1034 | 1033 | let region_scope = scope.region_scope; |
| 1035 | let scope_index = self.scopes.scope_index(region_scope, span); | |
| 1034 | let stack_index = self.scopes.stack_index(region_scope, span); | |
| 1036 | 1035 | let mut drops = DropTree::new(); |
| 1037 | 1036 | |
| 1038 | let drop_idx = self.scopes.scopes[scope_index + 1..] | |
| 1037 | let drop_idx = self.scopes.scopes[stack_index + 1..] | |
| 1039 | 1038 | .iter() |
| 1040 | 1039 | .flat_map(|scope| &scope.drops) |
| 1041 | 1040 | .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); |
| ... | ... | @@ -1066,14 +1065,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1066 | 1065 | .unwrap_or_else(|| span_bug!(source_info.span, "no if-then scope found")); |
| 1067 | 1066 | |
| 1068 | 1067 | let target = if_then_scope.region_scope; |
| 1069 | let scope_index = self.scopes.scope_index(target, source_info.span); | |
| 1068 | let stack_index = self.scopes.stack_index(target, source_info.span); | |
| 1070 | 1069 | |
| 1071 | 1070 | // Upgrade `if_then_scope` to `&mut`. |
| 1072 | 1071 | let if_then_scope = self.scopes.if_then_scope.as_mut().expect("upgrading & to &mut"); |
| 1073 | 1072 | |
| 1074 | 1073 | let mut drop_idx = ROOT_NODE; |
| 1075 | 1074 | let drops = &mut if_then_scope.else_drops; |
| 1076 | for scope in &self.scopes.scopes[scope_index + 1..] { | |
| 1075 | for scope in &self.scopes.scopes[stack_index + 1..] { | |
| 1077 | 1076 | for drop in &scope.drops { |
| 1078 | 1077 | drop_idx = drops.add_drop(*drop, drop_idx); |
| 1079 | 1078 | } |
| ... | ... | @@ -1390,47 +1389,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1390 | 1389 | // Scheduling drops |
| 1391 | 1390 | // ================ |
| 1392 | 1391 | |
| 1393 | pub(crate) fn schedule_drop_storage_and_value( | |
| 1394 | &mut self, | |
| 1395 | span: Span, | |
| 1396 | region_scope: region::Scope, | |
| 1397 | local: Local, | |
| 1398 | ) { | |
| 1399 | self.schedule_drop(span, region_scope, local, DropKind::Storage); | |
| 1400 | self.schedule_drop(span, region_scope, local, DropKind::Value); | |
| 1401 | } | |
| 1402 | ||
| 1403 | 1392 | /// Indicates that `place` should be dropped on exit from `region_scope`. |
| 1404 | 1393 | /// |
| 1405 | 1394 | /// When called with `DropKind::Storage`, `place` shouldn't be the return |
| 1406 | 1395 | /// place, or a function parameter. |
| 1407 | pub(crate) fn schedule_drop( | |
| 1396 | fn schedule_drop( | |
| 1408 | 1397 | &mut self, |
| 1409 | 1398 | span: Span, |
| 1410 | 1399 | region_scope: region::Scope, |
| 1411 | 1400 | local: Local, |
| 1412 | 1401 | drop_kind: DropKind, |
| 1413 | 1402 | ) { |
| 1414 | let needs_drop = match drop_kind { | |
| 1415 | DropKind::Value | DropKind::ForLint => { | |
| 1416 | if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) { | |
| 1417 | return; | |
| 1418 | } | |
| 1419 | true | |
| 1420 | } | |
| 1421 | DropKind::Storage => { | |
| 1422 | if local.index() <= self.arg_count { | |
| 1423 | span_bug!( | |
| 1424 | span, | |
| 1425 | "`schedule_drop` called with body argument {:?} \ | |
| 1426 | but its storage does not require a drop", | |
| 1427 | local, | |
| 1428 | ) | |
| 1429 | } | |
| 1430 | false | |
| 1431 | } | |
| 1432 | }; | |
| 1433 | ||
| 1434 | 1403 | // When building drops, we try to cache chains of drops to reduce the |
| 1435 | 1404 | // number of `DropTree::add_drop` calls. This, however, means that |
| 1436 | 1405 | // whenever we add a drop into a scope which already had some entries |
| ... | ... | @@ -1477,7 +1446,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1477 | 1446 | // path, we only need to invalidate the cache for drops that happen on |
| 1478 | 1447 | // the unwind or coroutine drop paths. This means that for |
| 1479 | 1448 | // non-coroutines we don't need to invalidate caches for `DropKind::Storage`. |
| 1480 | let invalidate_caches = needs_drop || self.coroutine.is_some(); | |
| 1449 | let invalidate_caches = match drop_kind { | |
| 1450 | DropKind::Value | DropKind::ForLint => true, | |
| 1451 | DropKind::Storage => self.coroutine.is_some(), | |
| 1452 | }; | |
| 1481 | 1453 | for scope in self.scopes.scopes.iter_mut().rev() { |
| 1482 | 1454 | if invalidate_caches { |
| 1483 | 1455 | scope.invalidate_cache(); |
| ... | ... | @@ -1501,6 +1473,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1501 | 1473 | span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); |
| 1502 | 1474 | } |
| 1503 | 1475 | |
| 1476 | /// Indicates that `place` should be marked `StorageDead` on exit from `region_scope`. | |
| 1477 | /// | |
| 1478 | /// `place` must not be the return place, or a function parameter. | |
| 1479 | pub(crate) fn schedule_drop_storage( | |
| 1480 | &mut self, | |
| 1481 | span: Span, | |
| 1482 | region_scope: region::Scope, | |
| 1483 | local: Local, | |
| 1484 | ) { | |
| 1485 | if local.index() <= self.arg_count { | |
| 1486 | span_bug!( | |
| 1487 | span, | |
| 1488 | "`schedule_drop` called with body argument {:?} \ | |
| 1489 | but its storage does not require a drop", | |
| 1490 | local, | |
| 1491 | ) | |
| 1492 | } | |
| 1493 | self.schedule_drop(span, region_scope, local, DropKind::Storage); | |
| 1494 | } | |
| 1495 | ||
| 1496 | /// Indicates that `place` should be dropped on exit from `region_scope`. | |
| 1497 | pub(crate) fn schedule_drop_value( | |
| 1498 | &mut self, | |
| 1499 | span: Span, | |
| 1500 | region_scope: region::Scope, | |
| 1501 | local: Local, | |
| 1502 | ) { | |
| 1503 | if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) { | |
| 1504 | return; | |
| 1505 | } | |
| 1506 | self.schedule_drop(span, region_scope, local, DropKind::Value); | |
| 1507 | } | |
| 1508 | ||
| 1504 | 1509 | /// Schedule emission of a backwards incompatible drop lint hint. |
| 1505 | 1510 | /// Applicable only to temporary values for now. |
| 1506 | 1511 | #[instrument(level = "debug", skip(self))] |
| ... | ... | @@ -1512,28 +1517,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1512 | 1517 | ) { |
| 1513 | 1518 | // Note that we are *not* gating BIDs here on whether they have significant destructor. |
| 1514 | 1519 | // We need to know all of them so that we can capture potential borrow-checking errors. |
| 1515 | for scope in self.scopes.scopes.iter_mut().rev() { | |
| 1516 | // Since we are inserting linting MIR statement, we have to invalidate the caches | |
| 1517 | scope.invalidate_cache(); | |
| 1518 | if scope.region_scope == region_scope { | |
| 1519 | let region_scope_span = region_scope.span(self.tcx, self.region_scope_tree); | |
| 1520 | let scope_end = self.tcx.sess.source_map().end_point(region_scope_span); | |
| 1521 | ||
| 1522 | scope.drops.push(DropData { | |
| 1523 | source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, | |
| 1524 | local, | |
| 1525 | kind: DropKind::ForLint, | |
| 1526 | }); | |
| 1527 | ||
| 1528 | return; | |
| 1529 | } | |
| 1530 | } | |
| 1531 | span_bug!( | |
| 1532 | span, | |
| 1533 | "region scope {:?} not in scope to drop {:?} for linting", | |
| 1534 | region_scope, | |
| 1535 | local | |
| 1536 | ); | |
| 1520 | self.schedule_drop(span, region_scope, local, DropKind::ForLint); | |
| 1537 | 1521 | } |
| 1538 | 1522 | |
| 1539 | 1523 | /// Indicates that the "local operand" stored in `local` is |
| ... | ... | @@ -1611,7 +1595,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1611 | 1595 | /// It is possible to unwind to some ancestor scope if some drop panics as |
| 1612 | 1596 | /// the program breaks out of a if-then scope. |
| 1613 | 1597 | fn diverge_cleanup_target(&mut self, target_scope: region::Scope, span: Span) -> DropIdx { |
| 1614 | let target = self.scopes.scope_index(target_scope, span); | |
| 1598 | let target = self.scopes.stack_index(target_scope, span); | |
| 1615 | 1599 | let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target] |
| 1616 | 1600 | .iter() |
| 1617 | 1601 | .enumerate() |
| ... | ... | @@ -1674,7 +1658,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |
| 1674 | 1658 | self.coroutine.is_some(), |
| 1675 | 1659 | "diverge_dropline_target is valid only for coroutine" |
| 1676 | 1660 | ); |
| 1677 | let target = self.scopes.scope_index(target_scope, span); | |
| 1661 | let target = self.scopes.stack_index(target_scope, span); | |
| 1678 | 1662 | let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target] |
| 1679 | 1663 | .iter() |
| 1680 | 1664 | .enumerate() |
compiler/rustc_resolve/src/build_reduced_graph.rs+1-1| ... | ... | @@ -475,7 +475,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { |
| 475 | 475 | } |
| 476 | 476 | |
| 477 | 477 | fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility { |
| 478 | match self.r.try_resolve_visibility(&self.parent_scope, vis, true) { | |
| 478 | match self.r.try_resolve_visibility(&self.parent_scope, vis, false) { | |
| 479 | 479 | Ok(vis) => vis, |
| 480 | 480 | Err(error) => { |
| 481 | 481 | self.r.delayed_vis_resolution_errors.push(DelayedVisResolutionError { |
compiler/rustc_resolve/src/ident.rs+4| ... | ... | @@ -1155,6 +1155,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 1155 | 1155 | resolution.as_ref().and_then(|r| r.non_glob_decl).filter(|b| Some(*b) != ignore_decl); |
| 1156 | 1156 | |
| 1157 | 1157 | if let Some(finalize) = finalize { |
| 1158 | // finalize implies that the module is fully expanded | |
| 1159 | assert!(!module.has_unexpanded_invocations()); | |
| 1158 | 1160 | return self.get_mut().finalize_module_binding( |
| 1159 | 1161 | ident, |
| 1160 | 1162 | orig_ident_span, |
| ... | ... | @@ -1219,6 +1221,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 1219 | 1221 | resolution.as_ref().and_then(|r| r.glob_decl).filter(|b| Some(*b) != ignore_decl); |
| 1220 | 1222 | |
| 1221 | 1223 | if let Some(finalize) = finalize { |
| 1224 | // finalize implies that the module is fully expanded | |
| 1225 | assert!(!module.has_unexpanded_invocations()); | |
| 1222 | 1226 | return self.get_mut().finalize_module_binding( |
| 1223 | 1227 | ident, |
| 1224 | 1228 | orig_ident_span, |
compiler/rustc_session/src/options.rs+2| ... | ... | @@ -2298,6 +2298,8 @@ options! { |
| 2298 | 2298 | `=LooseTypes` |
| 2299 | 2299 | `=Inline` |
| 2300 | 2300 | Multiple options can be combined with commas."), |
| 2301 | autodiff_post_passes: Option<String> = (None, parse_opt_string, [TRACKED], | |
| 2302 | "set llvm passes to run after enzyme (no passes run when it is empty)"), | |
| 2301 | 2303 | #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")] |
| 2302 | 2304 | binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], |
| 2303 | 2305 | "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ |
compiler/rustc_target/src/spec/mod.rs+1-1| ... | ... | @@ -991,7 +991,7 @@ crate::target_spec_enum! { |
| 991 | 991 | /// On PowerPC only: build for SPE. |
| 992 | 992 | PowerPcSpe = "powerpc-spe", |
| 993 | 993 | /// On x86-32/64, aarch64, and S390x: do not use any FPU or SIMD registers for the ABI. |
| 994 | Softfloat = "softfloat", "x86-softfloat", | |
| 994 | Softfloat = "softfloat", | |
| 995 | 995 | } |
| 996 | 996 | |
| 997 | 997 | parse_error_type = "rustc abi"; |
compiler/rustc_type_ir/src/visit.rs+4-4| ... | ... | @@ -167,7 +167,7 @@ impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for |
| 167 | 167 | } |
| 168 | 168 | } |
| 169 | 169 | |
| 170 | impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &T { | |
| 170 | impl<I: Interner, T: TypeVisitable<I> + ?Sized> TypeVisitable<I> for &T { | |
| 171 | 171 | fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { |
| 172 | 172 | (**self).visit_with(visitor) |
| 173 | 173 | } |
| ... | ... | @@ -179,7 +179,7 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> { |
| 179 | 179 | } |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> { | |
| 182 | impl<I: Interner, T: TypeVisitable<I> + ?Sized> TypeVisitable<I> for Box<T> { | |
| 183 | 183 | fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { |
| 184 | 184 | (**self).visit_with(visitor) |
| 185 | 185 | } |
| ... | ... | @@ -209,14 +209,14 @@ impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for Smal |
| 209 | 209 | // `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general |
| 210 | 210 | // case, because we can't return a new slice. But note that there are a couple |
| 211 | 211 | // of trivial impls of `TypeFoldable` for specific slice types elsewhere. |
| 212 | impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] { | |
| 212 | impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for [T] { | |
| 213 | 213 | fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { |
| 214 | 214 | walk_visitable_list!(visitor, self.iter()); |
| 215 | 215 | V::Result::output() |
| 216 | 216 | } |
| 217 | 217 | } |
| 218 | 218 | |
| 219 | impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> { | |
| 219 | impl<const N: usize, I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for [T; N] { | |
| 220 | 220 | fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { |
| 221 | 221 | walk_visitable_list!(visitor, self.iter()); |
| 222 | 222 | V::Result::output() |
library/alloc/src/boxed.rs+2| ... | ... | @@ -218,6 +218,8 @@ mod iter; |
| 218 | 218 | /// [`ThinBox`] implementation. |
| 219 | 219 | mod thin; |
| 220 | 220 | |
| 221 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 222 | pub use iter::BoxedArrayIntoIter; | |
| 221 | 223 | #[unstable(feature = "thin_box", issue = "92791")] |
| 222 | 224 | pub use thin::ThinBox; |
| 223 | 225 |
library/alloc/src/boxed/iter.rs+155-3| ... | ... | @@ -1,18 +1,19 @@ |
| 1 | 1 | use core::async_iter::AsyncIterator; |
| 2 | use core::iter::FusedIterator; | |
| 2 | use core::iter::{FusedIterator, TrustedLen}; | |
| 3 | use core::num::NonZero; | |
| 3 | 4 | use core::pin::Pin; |
| 4 | 5 | use core::slice; |
| 5 | 6 | use core::task::{Context, Poll}; |
| 6 | 7 | |
| 7 | use crate::alloc::Allocator; | |
| 8 | use crate::alloc::{Allocator, Global}; | |
| 8 | 9 | #[cfg(not(no_global_oom_handling))] |
| 9 | 10 | use crate::borrow::Cow; |
| 10 | 11 | use crate::boxed::Box; |
| 11 | 12 | #[cfg(not(no_global_oom_handling))] |
| 12 | 13 | use crate::string::String; |
| 13 | use crate::vec; | |
| 14 | 14 | #[cfg(not(no_global_oom_handling))] |
| 15 | 15 | use crate::vec::Vec; |
| 16 | use crate::{fmt, vec}; | |
| 16 | 17 | |
| 17 | 18 | #[stable(feature = "rust1", since = "1.0.0")] |
| 18 | 19 | impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> { |
| ... | ... | @@ -192,3 +193,154 @@ impl<'a> FromIterator<Cow<'a, str>> for Box<str> { |
| 192 | 193 | String::from_iter(iter).into_boxed_str() |
| 193 | 194 | } |
| 194 | 195 | } |
| 196 | ||
| 197 | /// This implementation is required to make sure that the `Box<[I; N]>: IntoIterator` | |
| 198 | /// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. | |
| 199 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 200 | impl<I, const N: usize, A: Allocator> !Iterator for Box<[I; N], A> {} | |
| 201 | ||
| 202 | /// This implementation is required to make sure that the `&Box<[I; N]>: IntoIterator` | |
| 203 | /// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. | |
| 204 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 205 | impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a Box<[I; N], A> {} | |
| 206 | ||
| 207 | /// This implementation is required to make sure that the `&mut Box<[I; N]>: IntoIterator` | |
| 208 | /// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. | |
| 209 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 210 | impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a mut Box<[I; N], A> {} | |
| 211 | ||
| 212 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 213 | impl<'a, T, const N: usize, A: Allocator> IntoIterator for &'a Box<[T; N], A> { | |
| 214 | type IntoIter = slice::Iter<'a, T>; | |
| 215 | type Item = &'a T; | |
| 216 | fn into_iter(self) -> slice::Iter<'a, T> { | |
| 217 | self.iter() | |
| 218 | } | |
| 219 | } | |
| 220 | ||
| 221 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 222 | impl<'a, T, const N: usize, A: Allocator> IntoIterator for &'a mut Box<[T; N], A> { | |
| 223 | type IntoIter = slice::IterMut<'a, T>; | |
| 224 | type Item = &'a mut T; | |
| 225 | fn into_iter(self) -> slice::IterMut<'a, T> { | |
| 226 | self.iter_mut() | |
| 227 | } | |
| 228 | } | |
| 229 | ||
| 230 | /// A by-value `Box<[T; N]>` iterator. | |
| 231 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 232 | #[rustc_insignificant_dtor] | |
| 233 | pub struct BoxedArrayIntoIter<T, const N: usize, A: Allocator = Global> { | |
| 234 | // FIXME: make a more efficient implementation (without the need to store capacity) | |
| 235 | inner: vec::IntoIter<T, A>, | |
| 236 | } | |
| 237 | ||
| 238 | impl<T, const N: usize, A: Allocator> BoxedArrayIntoIter<T, N, A> { | |
| 239 | /// Returns an immutable slice of all elements that have not been yielded | |
| 240 | /// yet. | |
| 241 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 242 | pub fn as_slice(&self) -> &[T] { | |
| 243 | self.inner.as_slice() | |
| 244 | } | |
| 245 | ||
| 246 | /// Returns a mutable slice of all elements that have not been yielded yet. | |
| 247 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 248 | pub fn as_mut_slice(&mut self) -> &mut [T] { | |
| 249 | self.inner.as_mut_slice() | |
| 250 | } | |
| 251 | } | |
| 252 | ||
| 253 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 254 | impl<T, const N: usize, A: Allocator> Iterator for BoxedArrayIntoIter<T, N, A> { | |
| 255 | type Item = T; | |
| 256 | fn next(&mut self) -> Option<Self::Item> { | |
| 257 | self.inner.next() | |
| 258 | } | |
| 259 | ||
| 260 | fn size_hint(&self) -> (usize, Option<usize>) { | |
| 261 | let len = self.len(); | |
| 262 | (len, Some(len)) | |
| 263 | } | |
| 264 | ||
| 265 | #[inline] | |
| 266 | fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc | |
| 267 | where | |
| 268 | Fold: FnMut(Acc, Self::Item) -> Acc, | |
| 269 | { | |
| 270 | self.inner.fold(init, fold) | |
| 271 | } | |
| 272 | ||
| 273 | fn count(self) -> usize { | |
| 274 | self.len() | |
| 275 | } | |
| 276 | ||
| 277 | fn last(mut self) -> Option<Self::Item> { | |
| 278 | self.next_back() | |
| 279 | } | |
| 280 | ||
| 281 | fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { | |
| 282 | self.inner.advance_by(n) | |
| 283 | } | |
| 284 | } | |
| 285 | ||
| 286 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 287 | impl<T, const N: usize, A: Allocator> DoubleEndedIterator for BoxedArrayIntoIter<T, N, A> { | |
| 288 | fn next_back(&mut self) -> Option<Self::Item> { | |
| 289 | self.inner.next_back() | |
| 290 | } | |
| 291 | ||
| 292 | #[inline] | |
| 293 | fn rfold<Acc, Fold>(self, init: Acc, rfold: Fold) -> Acc | |
| 294 | where | |
| 295 | Fold: FnMut(Acc, Self::Item) -> Acc, | |
| 296 | { | |
| 297 | self.inner.rfold(init, rfold) | |
| 298 | } | |
| 299 | ||
| 300 | fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { | |
| 301 | self.inner.advance_back_by(n) | |
| 302 | } | |
| 303 | } | |
| 304 | ||
| 305 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 306 | impl<T, const N: usize, A: Allocator> ExactSizeIterator for BoxedArrayIntoIter<T, N, A> { | |
| 307 | fn len(&self) -> usize { | |
| 308 | self.inner.len() | |
| 309 | } | |
| 310 | ||
| 311 | fn is_empty(&self) -> bool { | |
| 312 | self.inner.is_empty() | |
| 313 | } | |
| 314 | } | |
| 315 | ||
| 316 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 317 | impl<T, const N: usize, A: Allocator> FusedIterator for BoxedArrayIntoIter<T, N, A> {} | |
| 318 | ||
| 319 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 320 | unsafe impl<T, const N: usize, A: Allocator> TrustedLen for BoxedArrayIntoIter<T, N, A> {} | |
| 321 | ||
| 322 | #[cfg(not(no_global_oom_handling))] | |
| 323 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 324 | impl<T: Clone, const N: usize, A: Clone + Allocator> Clone for BoxedArrayIntoIter<T, N, A> { | |
| 325 | fn clone(&self) -> Self { | |
| 326 | Self { inner: self.inner.clone() } | |
| 327 | } | |
| 328 | } | |
| 329 | ||
| 330 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 331 | impl<T: fmt::Debug, const N: usize, A: Allocator> fmt::Debug for BoxedArrayIntoIter<T, N, A> { | |
| 332 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 333 | // Only print the elements that were not yielded yet: we cannot | |
| 334 | // access the yielded elements anymore. | |
| 335 | f.debug_tuple("BoxedArrayIntoIter").field(&self.as_slice()).finish() | |
| 336 | } | |
| 337 | } | |
| 338 | ||
| 339 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 340 | impl<T, const N: usize, A: Allocator> IntoIterator for Box<[T; N], A> { | |
| 341 | type IntoIter = BoxedArrayIntoIter<T, N, A>; | |
| 342 | type Item = T; | |
| 343 | fn into_iter(self) -> BoxedArrayIntoIter<T, N, A> { | |
| 344 | BoxedArrayIntoIter { inner: (self as Box<[T], A>).into_vec().into_iter() } | |
| 345 | } | |
| 346 | } |
library/alloc/src/io/impls.rs created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | use crate::boxed::Box; | |
| 2 | use crate::io::SizeHint; | |
| 3 | ||
| 4 | // ============================================================================= | |
| 5 | // Forwarding implementations | |
| 6 | ||
| 7 | #[doc(hidden)] | |
| 8 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 9 | impl<T> SizeHint for Box<T> { | |
| 10 | #[inline] | |
| 11 | fn lower_bound(&self) -> usize { | |
| 12 | SizeHint::lower_bound(&**self) | |
| 13 | } | |
| 14 | ||
| 15 | #[inline] | |
| 16 | fn upper_bound(&self) -> Option<usize> { | |
| 17 | SizeHint::upper_bound(&**self) | |
| 18 | } | |
| 19 | } | |
| 20 | ||
| 21 | // ============================================================================= | |
| 22 | // In-memory buffer implementations |
library/alloc/src/io/mod.rs+2-1| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | //! Traits, helpers, and type definitions for core I/O functionality. |
| 2 | 2 | |
| 3 | 3 | mod error; |
| 4 | mod impls; | |
| 4 | 5 | |
| 5 | 6 | #[unstable(feature = "raw_os_error_ty", issue = "107792")] |
| 6 | 7 | pub use core::io::RawOsError; |
| ... | ... | @@ -17,4 +18,4 @@ pub use core::io::{ |
| 17 | 18 | }; |
| 18 | 19 | #[doc(hidden)] |
| 19 | 20 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] |
| 20 | pub use core::io::{OsFunctions, chain, take}; | |
| 21 | pub use core::io::{IoHandle, OsFunctions, SizeHint, chain, take}; |
library/alloc/src/vec/into_iter.rs+1-1| ... | ... | @@ -552,7 +552,7 @@ where |
| 552 | 552 | #[doc(hidden)] |
| 553 | 553 | #[unstable(issue = "none", feature = "std_internals")] |
| 554 | 554 | #[rustc_unsafe_specialization_marker] |
| 555 | pub trait NonDrop {} | |
| 555 | trait NonDrop {} | |
| 556 | 556 | |
| 557 | 557 | // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr |
| 558 | 558 | // and thus we can't implement drop-handling |
library/core/src/array/iter.rs+4-1| ... | ... | @@ -34,6 +34,9 @@ impl<T, const N: usize> IntoIter<T, N> { |
| 34 | 34 | } |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | #[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")] | |
| 38 | impl<T, const N: usize> !Iterator for [T; N] {} | |
| 39 | ||
| 37 | 40 | // Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator` |
| 38 | 41 | // hides this implementation from explicit `.into_iter()` calls on editions < 2021, |
| 39 | 42 | // so those calls will still resolve to the slice implementation, by reference. |
| ... | ... | @@ -365,7 +368,7 @@ unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {} |
| 365 | 368 | #[doc(hidden)] |
| 366 | 369 | #[unstable(issue = "none", feature = "std_internals")] |
| 367 | 370 | #[rustc_unsafe_specialization_marker] |
| 368 | pub trait NonDrop {} | |
| 371 | trait NonDrop {} | |
| 369 | 372 | |
| 370 | 373 | // T: Copy as approximation for !Drop since get_unchecked does not advance self.alive |
| 371 | 374 | // and thus we can't implement drop-handling |
library/core/src/io/impls.rs created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | use crate::io::SizeHint; | |
| 2 | ||
| 3 | // ============================================================================= | |
| 4 | // Forwarding implementations | |
| 5 | ||
| 6 | #[doc(hidden)] | |
| 7 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 8 | impl<T> SizeHint for &mut T { | |
| 9 | #[inline] | |
| 10 | fn lower_bound(&self) -> usize { | |
| 11 | SizeHint::lower_bound(*self) | |
| 12 | } | |
| 13 | ||
| 14 | #[inline] | |
| 15 | fn upper_bound(&self) -> Option<usize> { | |
| 16 | SizeHint::upper_bound(*self) | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | // ============================================================================= | |
| 21 | // In-memory buffer implementations | |
| 22 | ||
| 23 | #[doc(hidden)] | |
| 24 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 25 | impl SizeHint for &[u8] { | |
| 26 | #[inline] | |
| 27 | fn lower_bound(&self) -> usize { | |
| 28 | self.len() | |
| 29 | } | |
| 30 | ||
| 31 | #[inline] | |
| 32 | fn upper_bound(&self) -> Option<usize> { | |
| 33 | Some(self.len()) | |
| 34 | } | |
| 35 | } |
library/core/src/io/mod.rs+23| ... | ... | @@ -3,7 +3,9 @@ |
| 3 | 3 | mod borrowed_buf; |
| 4 | 4 | mod cursor; |
| 5 | 5 | mod error; |
| 6 | mod impls; | |
| 6 | 7 | mod io_slice; |
| 8 | mod size_hint; | |
| 7 | 9 | mod util; |
| 8 | 10 | |
| 9 | 11 | #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] |
| ... | ... | @@ -25,5 +27,26 @@ pub use self::{ |
| 25 | 27 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] |
| 26 | 28 | pub use self::{ |
| 27 | 29 | error::{Custom, CustomOwner, OsFunctions}, |
| 30 | size_hint::SizeHint, | |
| 28 | 31 | util::{chain, take}, |
| 29 | 32 | }; |
| 33 | ||
| 34 | /// Marks that a type `T` can have IO traits such as [`Seek`], [`Write`], etc. automatically | |
| 35 | /// implemented for handle types like [`Arc`][arc] as well. | |
| 36 | /// | |
| 37 | /// This trait should only be implemented for types where `<&T as Trait>::method(&mut &value, ..)` | |
| 38 | /// would be identical to `<T as Trait>::method(&mut value, ..)`. | |
| 39 | /// | |
| 40 | /// [`File`][file] passes this test, as operations on `&File` and `File` both affect | |
| 41 | /// the same underlying file. | |
| 42 | /// `[u8]` fails, because any modification to `&mut &[u8]` would only affect a temporary | |
| 43 | /// and be lost after the method has been called. | |
| 44 | /// | |
| 45 | // FIXME(#74481): Hard-links required to link from `core` to `std` | |
| 46 | /// [file]: ../../std/fs/struct.File.html | |
| 47 | /// [arc]: ../../alloc/sync/struct.Arc.html | |
| 48 | /// [`Write`]: ../../std/io/trait.Write.html | |
| 49 | /// [`Seek`]: ../../std/io/trait.Seek.html | |
| 50 | #[doc(hidden)] | |
| 51 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 52 | pub trait IoHandle {} |
library/core/src/io/size_hint.rs created+60| ... | ... | @@ -0,0 +1,60 @@ |
| 1 | /// Internal trait used to allow for specialization in `Read::size_hint` and | |
| 2 | /// `Iterator::size_hint`. | |
| 3 | /// | |
| 4 | /// All types implement this through a blanket default implementation returning | |
| 5 | /// a hint of `(0, None)`. | |
| 6 | /// | |
| 7 | /// Implementors should only provide [`lower_bound`](SizeHint::lower_bound) and | |
| 8 | /// [`upper_bound`](SizeHint::upper_bound). | |
| 9 | /// [`size_hint`](SizeHint::size_hint) is provided as a `final` method to enforce | |
| 10 | /// correctness. | |
| 11 | #[doc(hidden)] | |
| 12 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 13 | pub trait SizeHint { | |
| 14 | /// Returns a lower bound on the number of elements this container-like item | |
| 15 | /// contains. | |
| 16 | /// For example, an array `[u8; 12]` could return any value between `0` and | |
| 17 | /// `12` inclusively as a correct implementation. | |
| 18 | /// | |
| 19 | /// Through specialization, all types implement this method returning a default | |
| 20 | /// value of `0`. | |
| 21 | /// | |
| 22 | /// Implementations *must* ensure the returned value is less than or equal to | |
| 23 | /// the true element count. | |
| 24 | fn lower_bound(&self) -> usize; | |
| 25 | ||
| 26 | /// Returns an upper bound on the number of elements this container-like item | |
| 27 | /// contains if it can be determined, otherwise `None`. | |
| 28 | /// | |
| 29 | /// Through specialization, all types implement this method returning a default | |
| 30 | /// value of `None`. | |
| 31 | /// | |
| 32 | /// Implementations *must* ensure the returned value is greater than or equal | |
| 33 | /// to the true element count. | |
| 34 | fn upper_bound(&self) -> Option<usize>; | |
| 35 | ||
| 36 | /// Returns an estimate for the number of elements this container like type | |
| 37 | /// contains. | |
| 38 | /// | |
| 39 | /// This is a `final` method, and is guaranteed to return | |
| 40 | /// `(self.lower_bound(), self.upper_bound())`. | |
| 41 | /// | |
| 42 | /// Without specialization, types implementing this trait will return `(0, None)`. | |
| 43 | final fn size_hint(&self) -> (usize, Option<usize>) { | |
| 44 | (self.lower_bound(), self.upper_bound()) | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | #[doc(hidden)] | |
| 49 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 50 | impl<T: ?Sized> SizeHint for T { | |
| 51 | #[inline] | |
| 52 | default fn lower_bound(&self) -> usize { | |
| 53 | 0 | |
| 54 | } | |
| 55 | ||
| 56 | #[inline] | |
| 57 | default fn upper_bound(&self) -> Option<usize> { | |
| 58 | None | |
| 59 | } | |
| 60 | } |
library/core/src/io/util.rs+59-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | use crate::fmt; | |
| 1 | use crate::io::SizeHint; | |
| 2 | use crate::{cmp, fmt}; | |
| 2 | 3 | |
| 3 | 4 | /// `Empty` ignores any data written via [`Write`], and will always be empty |
| 4 | 5 | /// (returning zero bytes) when read via [`Read`]. |
| ... | ... | @@ -13,6 +14,15 @@ use crate::fmt; |
| 13 | 14 | #[derive(Copy, Clone, Debug, Default)] |
| 14 | 15 | pub struct Empty; |
| 15 | 16 | |
| 17 | #[doc(hidden)] | |
| 18 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 19 | impl SizeHint for Empty { | |
| 20 | #[inline] | |
| 21 | fn upper_bound(&self) -> Option<usize> { | |
| 22 | Some(0) | |
| 23 | } | |
| 24 | } | |
| 25 | ||
| 16 | 26 | /// Creates a value that is always at EOF for reads, and ignores all data written. |
| 17 | 27 | /// |
| 18 | 28 | /// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`] |
| ... | ... | @@ -63,6 +73,20 @@ pub struct Repeat { |
| 63 | 73 | pub byte: u8, |
| 64 | 74 | } |
| 65 | 75 | |
| 76 | #[doc(hidden)] | |
| 77 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 78 | impl SizeHint for Repeat { | |
| 79 | #[inline] | |
| 80 | fn lower_bound(&self) -> usize { | |
| 81 | usize::MAX | |
| 82 | } | |
| 83 | ||
| 84 | #[inline] | |
| 85 | fn upper_bound(&self) -> Option<usize> { | |
| 86 | None | |
| 87 | } | |
| 88 | } | |
| 89 | ||
| 66 | 90 | /// Creates an instance of a reader that infinitely repeats one byte. |
| 67 | 91 | /// |
| 68 | 92 | /// All reads from this reader will succeed by filling the specified buffer with |
| ... | ... | @@ -145,6 +169,23 @@ pub struct Chain<T, U> { |
| 145 | 169 | pub done_first: bool, |
| 146 | 170 | } |
| 147 | 171 | |
| 172 | #[doc(hidden)] | |
| 173 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 174 | impl<T, U> SizeHint for Chain<T, U> { | |
| 175 | #[inline] | |
| 176 | fn lower_bound(&self) -> usize { | |
| 177 | SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) | |
| 178 | } | |
| 179 | ||
| 180 | #[inline] | |
| 181 | fn upper_bound(&self) -> Option<usize> { | |
| 182 | match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { | |
| 183 | (Some(first), Some(second)) => first.checked_add(second), | |
| 184 | _ => None, | |
| 185 | } | |
| 186 | } | |
| 187 | } | |
| 188 | ||
| 148 | 189 | impl<T, U> Chain<T, U> { |
| 149 | 190 | /// Consumes the `Chain`, returning the wrapped readers. |
| 150 | 191 | /// |
| ... | ... | @@ -253,6 +294,23 @@ pub struct Take<T> { |
| 253 | 294 | pub limit: u64, |
| 254 | 295 | } |
| 255 | 296 | |
| 297 | #[doc(hidden)] | |
| 298 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 299 | impl<T> SizeHint for Take<T> { | |
| 300 | #[inline] | |
| 301 | fn lower_bound(&self) -> usize { | |
| 302 | cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize | |
| 303 | } | |
| 304 | ||
| 305 | #[inline] | |
| 306 | fn upper_bound(&self) -> Option<usize> { | |
| 307 | match SizeHint::upper_bound(&self.inner) { | |
| 308 | Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize), | |
| 309 | None => self.limit.try_into().ok(), | |
| 310 | } | |
| 311 | } | |
| 312 | } | |
| 313 | ||
| 256 | 314 | impl<T> Take<T> { |
| 257 | 315 | /// Returns the number of bytes that can be read before this instance will |
| 258 | 316 | /// return EOF. |
library/core/src/iter/adapters/array_chunks.rs+3-9| ... | ... | @@ -1,8 +1,6 @@ |
| 1 | 1 | use crate::array; |
| 2 | 2 | use crate::iter::adapters::SourceIter; |
| 3 | use crate::iter::{ | |
| 4 | ByRefSized, FusedIterator, InPlaceIterable, TrustedFused, TrustedRandomAccessNoCoerce, | |
| 5 | }; | |
| 3 | use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedRandomAccessNoCoerce}; | |
| 6 | 4 | use crate::num::NonZero; |
| 7 | 5 | use crate::ops::{ControlFlow, NeverShortCircuit, Try}; |
| 8 | 6 | |
| ... | ... | @@ -128,15 +126,11 @@ where |
| 128 | 126 | self.next_back_remainder(); |
| 129 | 127 | |
| 130 | 128 | let mut acc = init; |
| 131 | let mut iter = ByRefSized(&mut self.iter).rev(); | |
| 132 | 129 | |
| 133 | 130 | // NB remainder is handled by `next_back_remainder`, so |
| 134 | // `next_chunk` can't return `Err` with non-empty remainder | |
| 131 | // `next_chunk_back` can't return `Err` with non-empty remainder | |
| 135 | 132 | // (assuming correct `I as ExactSizeIterator` impl). |
| 136 | while let Ok(mut chunk) = iter.next_chunk() { | |
| 137 | // FIXME: do not do double reverse | |
| 138 | // (we could instead add `next_chunk_back` for example) | |
| 139 | chunk.reverse(); | |
| 133 | while let Ok(chunk) = self.iter.next_chunk_back() { | |
| 140 | 134 | acc = f(acc, chunk)? |
| 141 | 135 | } |
| 142 | 136 |
library/core/src/mem/mod.rs+39-5| ... | ... | @@ -35,6 +35,7 @@ use crate::clone::TrivialClone; |
| 35 | 35 | use crate::cmp::Ordering; |
| 36 | 36 | use crate::marker::{Destruct, DiscriminantKind}; |
| 37 | 37 | use crate::panic::const_assert; |
| 38 | use crate::ub_checks::assert_unsafe_precondition; | |
| 38 | 39 | use crate::{clone, cmp, fmt, hash, intrinsics, ptr}; |
| 39 | 40 | |
| 40 | 41 | mod alignment; |
| ... | ... | @@ -1077,6 +1078,27 @@ pub const fn copy<T: Copy>(x: &T) -> T { |
| 1077 | 1078 | /// |
| 1078 | 1079 | /// [ub]: ../../reference/behavior-considered-undefined.html |
| 1079 | 1080 | /// |
| 1081 | /// If you have a raw pointer instead of a reference, you might be looking for | |
| 1082 | /// `src.cast::<Dst>().`[`read_unaligned()`](pointer#method.read_unaligned) instead. | |
| 1083 | /// | |
| 1084 | /// # Safety | |
| 1085 | /// | |
| 1086 | /// - Requires `size_of_val::<Src>(src) >= size_of::<Dst>()` | |
| 1087 | /// - The first `size_of::<Dst>()` bytes behind `src` must be *readable* | |
| 1088 | /// - The first `size_of::<Dst>()` bytes behind `src` must be *[valid]* | |
| 1089 | /// when interpreted as a `Dst`. | |
| 1090 | /// | |
| 1091 | /// On top of that, remember that most types have additional invariants beyond merely | |
| 1092 | /// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`] | |
| 1093 | /// is considered initialized (under the current implementation; this does not constitute | |
| 1094 | /// a stable guarantee) because the only requirement the compiler knows about it | |
| 1095 | /// is that the data pointer must be non-null. Creating such a `Vec<T>` does not cause | |
| 1096 | /// *immediate* undefined behavior, but will cause undefined behavior with most | |
| 1097 | /// safe operations (including dropping it). | |
| 1098 | /// | |
| 1099 | /// [valid]: ../../reference/behavior-considered-undefined.html#r-undefined.validity | |
| 1100 | /// [`Vec<T>`]: ../../std/vec/struct.Vec.html | |
| 1101 | /// | |
| 1080 | 1102 | /// # Examples |
| 1081 | 1103 | /// |
| 1082 | 1104 | /// ``` |
| ... | ... | @@ -1101,20 +1123,32 @@ pub const fn copy<T: Copy>(x: &T) -> T { |
| 1101 | 1123 | /// |
| 1102 | 1124 | /// // The contents of 'foo_array' should not have changed |
| 1103 | 1125 | /// assert_eq!(foo_array, [10]); |
| 1126 | /// | |
| 1127 | /// let bytes: &[u8] = &[1, 2, 3, 4, 5, 6, 7]; | |
| 1128 | /// assert_eq!( | |
| 1129 | /// unsafe { mem::transmute_copy::<[u8], u32>(bytes) }, | |
| 1130 | /// u32::from_ne_bytes(*bytes.first_chunk().unwrap()), | |
| 1131 | /// ); | |
| 1104 | 1132 | /// ``` |
| 1105 | 1133 | #[inline] |
| 1106 | 1134 | #[must_use] |
| 1107 | 1135 | #[track_caller] |
| 1108 | 1136 | #[stable(feature = "rust1", since = "1.0.0")] |
| 1109 | 1137 | #[rustc_const_stable(feature = "const_transmute_copy", since = "1.74.0")] |
| 1110 | pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst { | |
| 1111 | assert!( | |
| 1112 | size_of::<Src>() >= size_of::<Dst>(), | |
| 1113 | "cannot transmute_copy if Dst is larger than Src" | |
| 1138 | pub const unsafe fn transmute_copy<Src: ?Sized, Dst>(src: &Src) -> Dst { | |
| 1139 | // library UB because it's possible for the `Src` to be only a subset of the allocation | |
| 1140 | // and thus for a failure to not be immediate language UB | |
| 1141 | assert_unsafe_precondition!( | |
| 1142 | check_library_ub, | |
| 1143 | "cannot transmute_copy if Dst is larger than Src", | |
| 1144 | ( | |
| 1145 | src_size: usize = size_of_val::<Src>(src), | |
| 1146 | dst_size: usize = Dst::SIZE, | |
| 1147 | ) => src_size >= dst_size | |
| 1114 | 1148 | ); |
| 1115 | 1149 | |
| 1116 | 1150 | // If Dst has a higher alignment requirement, src might not be suitably aligned. |
| 1117 | if align_of::<Dst>() > align_of::<Src>() { | |
| 1151 | if align_of::<Dst>() > align_of_val::<Src>(src) { | |
| 1118 | 1152 | // SAFETY: `src` is a reference which is guaranteed to be valid for reads. |
| 1119 | 1153 | // The caller must guarantee that the actual transmutation is safe. |
| 1120 | 1154 | unsafe { ptr::read_unaligned(src as *const Src as *const Dst) } |
library/coretests/tests/mem.rs-26| ... | ... | @@ -138,32 +138,6 @@ fn test_transmute_copy_unaligned() { |
| 138 | 138 | assert_eq!(0_u64, unsafe { transmute_copy(&u.b) }); |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | #[test] | |
| 142 | #[cfg(panic = "unwind")] | |
| 143 | fn test_transmute_copy_grow_panics() { | |
| 144 | use std::panic; | |
| 145 | ||
| 146 | let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { | |
| 147 | let _unused: u64 = transmute_copy(&1_u8); | |
| 148 | })); | |
| 149 | ||
| 150 | match err { | |
| 151 | Ok(_) => unreachable!(), | |
| 152 | Err(payload) => { | |
| 153 | payload | |
| 154 | .downcast::<&'static str>() | |
| 155 | .and_then(|s| { | |
| 156 | if *s == "cannot transmute_copy if Dst is larger than Src" { | |
| 157 | Ok(s) | |
| 158 | } else { | |
| 159 | Err(s) | |
| 160 | } | |
| 161 | }) | |
| 162 | .unwrap_or_else(|p| panic::resume_unwind(p)); | |
| 163 | } | |
| 164 | } | |
| 165 | } | |
| 166 | ||
| 167 | 141 | #[test] |
| 168 | 142 | #[allow(dead_code)] |
| 169 | 143 | fn test_discriminant_send_sync() { |
library/std/src/fs.rs+2| ... | ... | @@ -1540,6 +1540,8 @@ impl Seek for File { |
| 1540 | 1540 | (&*self).stream_position() |
| 1541 | 1541 | } |
| 1542 | 1542 | } |
| 1543 | #[doc(hidden)] | |
| 1544 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 1543 | 1545 | impl crate::io::IoHandle for File {} |
| 1544 | 1546 | |
| 1545 | 1547 | impl Dir { |
library/std/src/io/buffered/bufreader.rs+2| ... | ... | @@ -580,6 +580,8 @@ impl<R: ?Sized + Seek> Seek for BufReader<R> { |
| 580 | 580 | } |
| 581 | 581 | } |
| 582 | 582 | |
| 583 | #[doc(hidden)] | |
| 584 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 583 | 585 | impl<T: ?Sized> SizeHint for BufReader<T> { |
| 584 | 586 | #[inline] |
| 585 | 587 | fn lower_bound(&self) -> usize { |
library/std/src/io/mod.rs+2-104| ... | ... | @@ -299,7 +299,7 @@ mod tests; |
| 299 | 299 | |
| 300 | 300 | use core::slice::memchr; |
| 301 | 301 | |
| 302 | use alloc_crate::io::OsFunctions; | |
| 302 | pub(crate) use alloc_crate::io::IoHandle; | |
| 303 | 303 | #[unstable(feature = "raw_os_error_ty", issue = "107792")] |
| 304 | 304 | pub use alloc_crate::io::RawOsError; |
| 305 | 305 | #[doc(hidden)] |
| ... | ... | @@ -315,6 +315,7 @@ pub use alloc_crate::io::{ |
| 315 | 315 | }; |
| 316 | 316 | #[stable(feature = "iovec", since = "1.36.0")] |
| 317 | 317 | pub use alloc_crate::io::{IoSlice, IoSliceMut}; |
| 318 | use alloc_crate::io::{OsFunctions, SizeHint}; | |
| 318 | 319 | |
| 319 | 320 | #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] |
| 320 | 321 | pub use self::buffered::WriterPanicked; |
| ... | ... | @@ -1980,21 +1981,6 @@ pub enum SeekFrom { |
| 1980 | 1981 | Current(#[stable(feature = "rust1", since = "1.0.0")] i64), |
| 1981 | 1982 | } |
| 1982 | 1983 | |
| 1983 | /// Marks that a type `T` can have IO traits such as [`Seek`], [`Write`], etc. automatically | |
| 1984 | /// implemented for handle types like [`Arc`][arc] as well. | |
| 1985 | /// | |
| 1986 | /// This trait should only be implemented for types where `<&T as Trait>::method(&mut &value, ..)` | |
| 1987 | /// would be identical to `<T as Trait>::method(&mut value, ..)`. | |
| 1988 | /// | |
| 1989 | /// [`File`][file] passes this test, as operations on `&File` and `File` both affect | |
| 1990 | /// the same underlying file. | |
| 1991 | /// `[u8]` fails, because any modification to `&mut &[u8]` would only affect a temporary | |
| 1992 | /// and be lost after the method has been called. | |
| 1993 | /// | |
| 1994 | /// [file]: crate::fs::File | |
| 1995 | /// [arc]: crate::sync::Arc | |
| 1996 | pub(crate) trait IoHandle {} | |
| 1997 | ||
| 1998 | 1984 | fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> Result<usize> { |
| 1999 | 1985 | let mut read = 0; |
| 2000 | 1986 | loop { |
| ... | ... | @@ -2552,21 +2538,6 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> { |
| 2552 | 2538 | // split between the two parts of the chain |
| 2553 | 2539 | } |
| 2554 | 2540 | |
| 2555 | impl<T, U> SizeHint for Chain<T, U> { | |
| 2556 | #[inline] | |
| 2557 | fn lower_bound(&self) -> usize { | |
| 2558 | SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) | |
| 2559 | } | |
| 2560 | ||
| 2561 | #[inline] | |
| 2562 | fn upper_bound(&self) -> Option<usize> { | |
| 2563 | match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { | |
| 2564 | (Some(first), Some(second)) => first.checked_add(second), | |
| 2565 | _ => None, | |
| 2566 | } | |
| 2567 | } | |
| 2568 | } | |
| 2569 | ||
| 2570 | 2541 | #[stable(feature = "rust1", since = "1.0.0")] |
| 2571 | 2542 | impl<T: Read> Read for Take<T> { |
| 2572 | 2543 | fn read(&mut self, buf: &mut [u8]) -> Result<usize> { |
| ... | ... | @@ -2661,21 +2632,6 @@ impl<T: BufRead> BufRead for Take<T> { |
| 2661 | 2632 | } |
| 2662 | 2633 | } |
| 2663 | 2634 | |
| 2664 | impl<T> SizeHint for Take<T> { | |
| 2665 | #[inline] | |
| 2666 | fn lower_bound(&self) -> usize { | |
| 2667 | cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize | |
| 2668 | } | |
| 2669 | ||
| 2670 | #[inline] | |
| 2671 | fn upper_bound(&self) -> Option<usize> { | |
| 2672 | match SizeHint::upper_bound(&self.inner) { | |
| 2673 | Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize), | |
| 2674 | None => self.limit.try_into().ok(), | |
| 2675 | } | |
| 2676 | } | |
| 2677 | } | |
| 2678 | ||
| 2679 | 2635 | #[stable(feature = "seek_io_take", since = "1.89.0")] |
| 2680 | 2636 | impl<T: Seek> Seek for Take<T> { |
| 2681 | 2637 | fn seek(&mut self, pos: SeekFrom) -> Result<u64> { |
| ... | ... | @@ -2784,64 +2740,6 @@ fn uninlined_slow_read_byte<R: Read>(reader: &mut R) -> Option<Result<u8>> { |
| 2784 | 2740 | inlined_slow_read_byte(reader) |
| 2785 | 2741 | } |
| 2786 | 2742 | |
| 2787 | trait SizeHint { | |
| 2788 | fn lower_bound(&self) -> usize; | |
| 2789 | ||
| 2790 | fn upper_bound(&self) -> Option<usize>; | |
| 2791 | ||
| 2792 | fn size_hint(&self) -> (usize, Option<usize>) { | |
| 2793 | (self.lower_bound(), self.upper_bound()) | |
| 2794 | } | |
| 2795 | } | |
| 2796 | ||
| 2797 | impl<T: ?Sized> SizeHint for T { | |
| 2798 | #[inline] | |
| 2799 | default fn lower_bound(&self) -> usize { | |
| 2800 | 0 | |
| 2801 | } | |
| 2802 | ||
| 2803 | #[inline] | |
| 2804 | default fn upper_bound(&self) -> Option<usize> { | |
| 2805 | None | |
| 2806 | } | |
| 2807 | } | |
| 2808 | ||
| 2809 | impl<T> SizeHint for &mut T { | |
| 2810 | #[inline] | |
| 2811 | fn lower_bound(&self) -> usize { | |
| 2812 | SizeHint::lower_bound(*self) | |
| 2813 | } | |
| 2814 | ||
| 2815 | #[inline] | |
| 2816 | fn upper_bound(&self) -> Option<usize> { | |
| 2817 | SizeHint::upper_bound(*self) | |
| 2818 | } | |
| 2819 | } | |
| 2820 | ||
| 2821 | impl<T> SizeHint for Box<T> { | |
| 2822 | #[inline] | |
| 2823 | fn lower_bound(&self) -> usize { | |
| 2824 | SizeHint::lower_bound(&**self) | |
| 2825 | } | |
| 2826 | ||
| 2827 | #[inline] | |
| 2828 | fn upper_bound(&self) -> Option<usize> { | |
| 2829 | SizeHint::upper_bound(&**self) | |
| 2830 | } | |
| 2831 | } | |
| 2832 | ||
| 2833 | impl SizeHint for &[u8] { | |
| 2834 | #[inline] | |
| 2835 | fn lower_bound(&self) -> usize { | |
| 2836 | self.len() | |
| 2837 | } | |
| 2838 | ||
| 2839 | #[inline] | |
| 2840 | fn upper_bound(&self) -> Option<usize> { | |
| 2841 | Some(self.len()) | |
| 2842 | } | |
| 2843 | } | |
| 2844 | ||
| 2845 | 2743 | /// An iterator over the contents of an instance of `BufRead` split on a |
| 2846 | 2744 | /// particular byte. |
| 2847 | 2745 | /// |
library/std/src/io/util.rs+1-20| ... | ... | @@ -6,7 +6,7 @@ mod tests; |
| 6 | 6 | use crate::fmt; |
| 7 | 7 | use crate::io::{ |
| 8 | 8 | self, BorrowedCursor, BufRead, Empty, IoSlice, IoSliceMut, Read, Repeat, Seek, SeekFrom, Sink, |
| 9 | SizeHint, Write, | |
| 9 | Write, | |
| 10 | 10 | }; |
| 11 | 11 | |
| 12 | 12 | #[stable(feature = "rust1", since = "1.0.0")] |
| ... | ... | @@ -102,13 +102,6 @@ impl Seek for Empty { |
| 102 | 102 | } |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | impl SizeHint for Empty { | |
| 106 | #[inline] | |
| 107 | fn upper_bound(&self) -> Option<usize> { | |
| 108 | Some(0) | |
| 109 | } | |
| 110 | } | |
| 111 | ||
| 112 | 105 | #[stable(feature = "empty_write", since = "1.73.0")] |
| 113 | 106 | impl Write for Empty { |
| 114 | 107 | #[inline] |
| ... | ... | @@ -240,18 +233,6 @@ impl Read for Repeat { |
| 240 | 233 | } |
| 241 | 234 | } |
| 242 | 235 | |
| 243 | impl SizeHint for Repeat { | |
| 244 | #[inline] | |
| 245 | fn lower_bound(&self) -> usize { | |
| 246 | usize::MAX | |
| 247 | } | |
| 248 | ||
| 249 | #[inline] | |
| 250 | fn upper_bound(&self) -> Option<usize> { | |
| 251 | None | |
| 252 | } | |
| 253 | } | |
| 254 | ||
| 255 | 236 | #[stable(feature = "rust1", since = "1.0.0")] |
| 256 | 237 | impl Write for Sink { |
| 257 | 238 | #[inline] |
library/test/src/lib.rs+9| ... | ... | @@ -207,6 +207,14 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { |
| 207 | 207 | // If we're being run in SpawnedSecondary mode, run the test here. run_test |
| 208 | 208 | // will then exit the process. |
| 209 | 209 | if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) { |
| 210 | // SAFETY: Technically, this is a racy access that we probably shouldn't do? | |
| 211 | // In practice, this is completely fine as long as the test harness is made of Rust, | |
| 212 | // as std will synchronize the racy accesses that occur when they happen through std::env. | |
| 213 | // Any unsoundness can only be exposed in practice if e.g. C code also takes an interest | |
| 214 | // in these variables. | |
| 215 | // | |
| 216 | // If we ever grow an actual story for libtest and start documenting custom harness reqs, | |
| 217 | // we should either fix this being racy or say "write it in Rust, please". | |
| 210 | 218 | unsafe { |
| 211 | 219 | env::remove_var(SECONDARY_TEST_INVOKER_VAR); |
| 212 | 220 | } |
| ... | ... | @@ -214,6 +222,7 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { |
| 214 | 222 | // Convert benchmarks to tests if we're not benchmarking. |
| 215 | 223 | let mut tests = tests.iter().map(make_owned_test).collect::<Vec<_>>(); |
| 216 | 224 | if env::var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR).is_ok() { |
| 225 | // SAFETY: Same as for SECONDARY_TEST_INVOKER_VAR | |
| 217 | 226 | unsafe { |
| 218 | 227 | env::remove_var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR); |
| 219 | 228 | } |
src/ci/docker/host-x86_64/tidy/Dockerfile+1-2| ... | ... | @@ -41,5 +41,4 @@ COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/ |
| 41 | 41 | |
| 42 | 42 | # NOTE: intentionally uses python2 for x.py so we can test it still works. |
| 43 | 43 | # validate-toolstate only runs in our CI, so it's ok for it to only support python3. |
| 44 | ENV SCRIPT="TIDY_PRINT_DIFF=1 python2.7 ../x.py test \ | |
| 45 | src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck" | |
| 44 | ENV SCRIPT="python2.7 ../x.py test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck" |
src/ci/docker/scripts/rfl-build.sh+2-1| ... | ... | @@ -2,7 +2,8 @@ |
| 2 | 2 | |
| 3 | 3 | set -euo pipefail |
| 4 | 4 | |
| 5 | LINUX_VERSION=v7.1-rc1 | |
| 5 | # https://github.com/rust-lang/rust/pull/157151 | |
| 6 | LINUX_VERSION=40bc55834bc15896f4438b0936c679ef32e20df1 | |
| 6 | 7 | |
| 7 | 8 | # Build rustc, rustdoc, cargo, clippy-driver and rustfmt |
| 8 | 9 | ../x.py build --stage 2 library rustdoc clippy rustfmt |
src/etc/pre-push.sh+1-2| ... | ... | @@ -33,8 +33,7 @@ ROOT_DIR="$(git rev-parse --show-toplevel)" |
| 33 | 33 | echo "Running pre-push script $ROOT_DIR/x test tidy" |
| 34 | 34 | |
| 35 | 35 | cd "$ROOT_DIR" |
| 36 | # The env var is necessary for printing diffs in py (fmt/lint) and cpp. | |
| 37 | TIDY_PRINT_DIFF=1 ./x test tidy \ | |
| 36 | ./x test tidy \ | |
| 38 | 37 | --set build.locked-deps=true \ |
| 39 | 38 | --extra-checks auto:py,auto:cpp,auto:js |
| 40 | 39 | if [ $? -ne 0 ]; then |
src/librustdoc/clean/inline.rs+22-15| ... | ... | @@ -681,21 +681,26 @@ fn build_module( |
| 681 | 681 | // We are only interested into `Res::Def`. And in there, we only want "items" which get their own |
| 682 | 682 | // rustdoc page. So not `DefKind::Ctor` for example (which is returned by `tcx.module_children()`). |
| 683 | 683 | fn should_ignore_res(res: Res) -> bool { |
| 684 | !matches!(res, Res::Def(def_kind, _) if !should_ignore_def_kind(def_kind)) | |
| 685 | } | |
| 686 | ||
| 687 | fn should_ignore_def_kind(kind: DefKind) -> bool { | |
| 684 | 688 | !matches!( |
| 685 | res, | |
| 686 | Res::Def(DefKind::Trait, _) | |
| 687 | | Res::Def(DefKind::TraitAlias, _) | |
| 688 | | Res::Def(DefKind::Fn, _) | |
| 689 | | Res::Def(DefKind::Struct, _) | |
| 690 | | Res::Def(DefKind::Union, _) | |
| 691 | | Res::Def(DefKind::TyAlias, _) | |
| 692 | | Res::Def(DefKind::Enum, _) | |
| 693 | | Res::Def(DefKind::ForeignTy, _) | |
| 694 | | Res::Def(DefKind::Variant, _) | |
| 695 | | Res::Def(DefKind::Mod, _) | |
| 696 | | Res::Def(DefKind::Static { .. }, _) | |
| 697 | | Res::Def(DefKind::Const { .. }, _) | |
| 698 | | Res::Def(DefKind::Macro(_), _) | |
| 689 | kind, | |
| 690 | DefKind::Trait | |
| 691 | | DefKind::TraitAlias | |
| 692 | | DefKind::Fn | |
| 693 | | DefKind::Struct | |
| 694 | | DefKind::Union | |
| 695 | | DefKind::TyAlias | |
| 696 | | DefKind::Enum | |
| 697 | | DefKind::ForeignTy | |
| 698 | | DefKind::Variant | |
| 699 | | DefKind::Mod | |
| 700 | | DefKind::Static { .. } | |
| 701 | | DefKind::Const { .. } | |
| 702 | | DefKind::Macro(_) | |
| 703 | | DefKind::Use | |
| 699 | 704 | ) |
| 700 | 705 | } |
| 701 | 706 | |
| ... | ... | @@ -770,13 +775,15 @@ fn build_module_items( |
| 770 | 775 | } else if let Some(def_id) = res.opt_def_id() |
| 771 | 776 | && let Some(reexport) = item.reexport_chain.first() |
| 772 | 777 | && let Some(reexport_def_id) = reexport.id() |
| 778 | && !should_ignore_def_kind(cx.tcx.def_kind(reexport_def_id)) | |
| 773 | 779 | && find_attr!( |
| 774 | 780 | load_attrs(cx.tcx, reexport_def_id), |
| 775 | 781 | Doc(d) |
| 776 | 782 | if d.inline.first().is_some_and(|(inline, _)| *inline == hir::attrs::DocInline::NoInline) |
| 777 | 783 | ) |
| 778 | 784 | { |
| 779 | if should_ignore_res(res) { | |
| 785 | // We don't inline foreign `use`. | |
| 786 | if should_ignore_res(res) || matches!(res, Res::Def(DefKind::Use, _)) { | |
| 780 | 787 | continue; |
| 781 | 788 | } |
| 782 | 789 | // This item is reexported as `no_inline` so it shouldn't be inlined. |
src/tools/miri/tests/x86_64-unknown-kernel.json+1-1| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | "vendor": "unknown", |
| 11 | 11 | "linker": "rust-lld", |
| 12 | 12 | "linker-flavor": "gnu-lld", |
| 13 | "rustc-abi": "x86-softfloat", | |
| 13 | "rustc-abi": "softfloat", | |
| 14 | 14 | "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float", |
| 15 | 15 | "dynamic-linking": false, |
| 16 | 16 | "executables": true, |
src/tools/tidy/src/deps.rs+3| ... | ... | @@ -692,6 +692,9 @@ pub fn check(root: &Path, cargo: &Path, tidy_ctx: TidyCtx) { |
| 692 | 692 | |
| 693 | 693 | /// Ensure the list of proc-macro crate transitive dependencies is up to date |
| 694 | 694 | fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, check: &mut RunningCheck) { |
| 695 | if std::env::var("RUSTC").is_err() { | |
| 696 | panic!("tidy must be run under bootstrap (./x test tidy), not as a standalone command"); | |
| 697 | } | |
| 695 | 698 | let mut cmd = cargo_metadata::MetadataCommand::new(); |
| 696 | 699 | cmd.cargo_path(cargo) |
| 697 | 700 | .manifest_path(root.join("Cargo.toml")) |
src/tools/tidy/src/extra_checks/mod.rs+17-22| ... | ... | @@ -10,12 +10,11 @@ |
| 10 | 10 | //! configuration after a double dash (`--extra-checks=py -- foo.py`) |
| 11 | 11 | //! 2. Build configuration based on args/environment: |
| 12 | 12 | //! - Formatters by default are in check only mode |
| 13 | //! - If in CI (TIDY_PRINT_DIFF=1 is set), check and print the diff | |
| 14 | 13 | //! - If `--bless` is provided, formatters may run |
| 15 | 14 | //! - Pass any additional config after the `--`. If no files are specified, |
| 16 | 15 | //! use a default. |
| 17 | //! 3. Print the output of the given command. If it fails and `TIDY_PRINT_DIFF` | |
| 18 | //! is set, rerun the tool to print a suggestion diff (for e.g. CI) | |
| 16 | //! 3. Print the output of the given command. If it fails, rerun the tool to print a suggestion | |
| 17 | //! diff. | |
| 19 | 18 | |
| 20 | 19 | use std::ffi::{OsStr, OsString}; |
| 21 | 20 | use std::path::{Path, PathBuf}; |
| ... | ... | @@ -200,14 +199,12 @@ fn js_prepare(root_path: &Path, outdir: &Path, npm: &Path, tidy_ctx: &TidyCtx) - |
| 200 | 199 | |
| 201 | 200 | fn show_bless_help(mode: &str, action: &str, bless: bool) { |
| 202 | 201 | if !bless { |
| 203 | eprintln!("rerun tidy with `--extra-checks={mode} --bless` to {action}"); | |
| 202 | eprintln!( | |
| 203 | "rerun with `--bless` to {action}: `./x.py test tidy --extra-checks={mode} --bless`" | |
| 204 | ); | |
| 204 | 205 | } |
| 205 | 206 | } |
| 206 | 207 | |
| 207 | fn show_diff() -> bool { | |
| 208 | std::env::var("TIDY_PRINT_DIFF").is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1") | |
| 209 | } | |
| 210 | ||
| 211 | 208 | fn check_spellcheck(root_path: &Path, outdir: &Path, cargo: &Path, tidy_ctx: &TidyCtx) { |
| 212 | 209 | let mut check = tidy_ctx.start_check("extra_checks:spellcheck"); |
| 213 | 210 | |
| ... | ... | @@ -314,7 +311,7 @@ fn check_python_lint( |
| 314 | 311 | |
| 315 | 312 | let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, args); |
| 316 | 313 | |
| 317 | if res.is_err() && !bless && show_diff() { | |
| 314 | if res.is_err() && !bless { | |
| 318 | 315 | eprintln!("\npython linting failed! Printing diff suggestions:"); |
| 319 | 316 | |
| 320 | 317 | let diff_res = run_ruff( |
| ... | ... | @@ -358,18 +355,16 @@ fn check_python_fmt( |
| 358 | 355 | let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &args); |
| 359 | 356 | |
| 360 | 357 | if res.is_err() && !bless { |
| 361 | if show_diff() { | |
| 362 | eprintln!("\npython formatting does not match! Printing diff:"); | |
| 363 | ||
| 364 | let _ = run_ruff( | |
| 365 | root_path, | |
| 366 | outdir, | |
| 367 | py_path, | |
| 368 | &cfg_args, | |
| 369 | &file_args, | |
| 370 | &["format".as_ref(), "--diff".as_ref()], | |
| 371 | ); | |
| 372 | } | |
| 358 | eprintln!("\npython formatting does not match! Printing diff:"); | |
| 359 | ||
| 360 | let _ = run_ruff( | |
| 361 | root_path, | |
| 362 | outdir, | |
| 363 | py_path, | |
| 364 | &cfg_args, | |
| 365 | &file_args, | |
| 366 | &["format".as_ref(), "--diff".as_ref()], | |
| 367 | ); | |
| 373 | 368 | show_bless_help("py:fmt", "reformat Python code", bless); |
| 374 | 369 | } |
| 375 | 370 | |
| ... | ... | @@ -421,7 +416,7 @@ fn check_cpp_fmt( |
| 421 | 416 | let args = merge_args(&cfg_args_clang_format, &file_args_clang_format); |
| 422 | 417 | let res = py_runner(py_path, false, None, "clang-format", &args); |
| 423 | 418 | |
| 424 | if res.is_err() && !bless && show_diff() { | |
| 419 | if res.is_err() && !bless { | |
| 425 | 420 | eprintln!("\nclang-format linting failed! Printing diff suggestions:"); |
| 426 | 421 | |
| 427 | 422 | let mut cfg_args_diff = cfg_args.clone(); |
tests/codegen-llvm/autodiff/abi_handling.rs+18-18| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | //@ revisions: debug release |
| 2 | 2 | |
| 3 | 3 | //@[debug] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=0 -Clto=fat |
| 4 | //@[release] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat | |
| 4 | //@[release] compile-flags: -Zautodiff=Enable,NoTT -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 5 | 5 | //@ no-prefer-dynamic |
| 6 | 6 | //@ needs-enzyme |
| 7 | 7 | |
| ... | ... | @@ -39,15 +39,15 @@ fn square(x: f32) -> f32 { |
| 39 | 39 | // CHECK-NEXT: Function Attrs |
| 40 | 40 | // debug-NEXT: define internal { float, float } |
| 41 | 41 | // debug-SAME: (ptr {{.*}}%x, ptr {{.*}}%bx_0) |
| 42 | // release-NEXT: define internal fastcc float | |
| 43 | // release-SAME: (float %x.0.val, float %x.4.val) | |
| 42 | // release-NEXT: define internal fastcc { float, float } | |
| 43 | // release-SAME: (ptr {{.*}}%x) | |
| 44 | 44 | |
| 45 | 45 | // CHECK-LABEL: ; abi_handling::f1 |
| 46 | 46 | // CHECK-NEXT: Function Attrs |
| 47 | 47 | // debug-NEXT: define internal float |
| 48 | 48 | // debug-SAME: (ptr {{.*}}%x) |
| 49 | // release-NEXT: define internal fastcc noundef float | |
| 50 | // release-SAME: (float %x.0.val, float %x.4.val) | |
| 49 | // release-NEXT: define internal noundef float | |
| 50 | // release-SAME: (ptr {{.*}}%x) | |
| 51 | 51 | #[autodiff_forward(df1, Dual, Dual)] |
| 52 | 52 | #[inline(never)] |
| 53 | 53 | fn f1(x: &[f32; 2]) -> f32 { |
| ... | ... | @@ -58,15 +58,15 @@ fn f1(x: &[f32; 2]) -> f32 { |
| 58 | 58 | // CHECK-NEXT: Function Attrs |
| 59 | 59 | // debug-NEXT: define internal { float, float } |
| 60 | 60 | // debug-SAME: (ptr %f, float %x, float %dret) |
| 61 | // release-NEXT: define internal fastcc noundef float | |
| 61 | // release-NEXT: define internal fastcc { float, float } | |
| 62 | 62 | // release-SAME: (float noundef %x) |
| 63 | 63 | |
| 64 | 64 | // CHECK-LABEL: ; abi_handling::f2 |
| 65 | 65 | // CHECK-NEXT: Function Attrs |
| 66 | 66 | // debug-NEXT: define internal float |
| 67 | 67 | // debug-SAME: (ptr %f, float %x) |
| 68 | // release-NEXT: define internal fastcc noundef float | |
| 69 | // release-SAME: (float noundef %x) | |
| 68 | // release-NEXT: define internal noundef float | |
| 69 | // release-SAME: (ptr {{.*}}%f, float {{.*}}%x) | |
| 70 | 70 | #[autodiff_reverse(df2, Const, Active, Active)] |
| 71 | 71 | #[inline(never)] |
| 72 | 72 | fn f2(f: fn(f32) -> f32, x: f32) -> f32 { |
| ... | ... | @@ -77,15 +77,15 @@ fn f2(f: fn(f32) -> f32, x: f32) -> f32 { |
| 77 | 77 | // CHECK-NEXT: Function Attrs |
| 78 | 78 | // debug-NEXT: define internal { float, float } |
| 79 | 79 | // debug-SAME: (ptr align 4 %x, ptr align 4 %bx_0, ptr align 4 %y, ptr align 4 %by_0) |
| 80 | // release-NEXT: define internal fastcc float | |
| 81 | // release-SAME: (float %x.0.val) | |
| 80 | // release-NEXT: define internal fastcc { float, float } | |
| 81 | // release-SAME: (ptr {{.*}}%x) | |
| 82 | 82 | |
| 83 | 83 | // CHECK-LABEL: ; abi_handling::f3 |
| 84 | 84 | // CHECK-NEXT: Function Attrs |
| 85 | 85 | // debug-NEXT: define internal float |
| 86 | 86 | // debug-SAME: (ptr {{.*}}%x, ptr {{.*}}%y) |
| 87 | // release-NEXT: define internal fastcc noundef float | |
| 88 | // release-SAME: (float %x.0.val) | |
| 87 | // release-NEXT: define internal noundef float | |
| 88 | // release-SAME: (ptr {{.*}}%y) | |
| 89 | 89 | #[autodiff_forward(df3, Dual, Dual, Dual)] |
| 90 | 90 | #[inline(never)] |
| 91 | 91 | fn f3<'a>(x: &'a f32, y: &'a f32) -> f32 { |
| ... | ... | @@ -103,7 +103,7 @@ fn f3<'a>(x: &'a f32, y: &'a f32) -> f32 { |
| 103 | 103 | // CHECK-NEXT: Function Attrs |
| 104 | 104 | // debug-NEXT: define internal float |
| 105 | 105 | // debug-SAME: (float %x.0, float %x.1) |
| 106 | // release-NEXT: define internal fastcc noundef float | |
| 106 | // release-NEXT: define internal noundef float | |
| 107 | 107 | // release-SAME: (float noundef %x.0, float noundef %x.1) |
| 108 | 108 | #[autodiff_forward(df4, Dual, Dual)] |
| 109 | 109 | #[inline(never)] |
| ... | ... | @@ -122,7 +122,7 @@ fn f4(x: (f32, f32)) -> f32 { |
| 122 | 122 | // CHECK-NEXT: Function Attrs |
| 123 | 123 | // debug-NEXT: define internal float |
| 124 | 124 | // debug-SAME: (float %i.0, float %i.1) |
| 125 | // release-NEXT: define internal fastcc noundef float | |
| 125 | // release-NEXT: define internal noundef float | |
| 126 | 126 | // release-SAME: (float noundef %i.0, float noundef %i.1) |
| 127 | 127 | #[autodiff_forward(df5, Dual, Dual)] |
| 128 | 128 | #[inline(never)] |
| ... | ... | @@ -142,7 +142,7 @@ fn f5(i: Input) -> f32 { |
| 142 | 142 | // CHECK-NEXT: Function Attrs |
| 143 | 143 | // debug-NEXT: define internal float |
| 144 | 144 | // debug-SAME: (float %i.0, float %i.1) |
| 145 | // release-NEXT: define internal fastcc noundef float | |
| 145 | // release-NEXT: define internal noundef float | |
| 146 | 146 | // release-SAME: (float noundef %i.0, float noundef %i.1) |
| 147 | 147 | #[autodiff_forward(df6, Dual, Dual)] |
| 148 | 148 | #[inline(never)] |
| ... | ... | @@ -155,14 +155,14 @@ fn f6(i: NestedInput) -> f32 { |
| 155 | 155 | // debug-NEXT: define internal { float, float } |
| 156 | 156 | // debug-SAME: (ptr align 4 %x.0, ptr align 4 %x.1, ptr align 4 %bx_0.0, ptr align 4 %bx_0.1) |
| 157 | 157 | // release-NEXT: define internal fastcc { float, float } |
| 158 | // release-SAME: (float %x.0.0.val, float %x.1.0.val) | |
| 158 | // release-SAME: (ptr {{.*}}%x.0, ptr {{.*}}%x.1) | |
| 159 | 159 | |
| 160 | 160 | // CHECK-LABEL: ; abi_handling::f7 |
| 161 | 161 | // CHECK-NEXT: Function Attrs |
| 162 | 162 | // debug-NEXT: define internal float |
| 163 | 163 | // debug-SAME: (ptr {{.*}}%x.0, ptr {{.*}}%x.1) |
| 164 | // release-NEXT: define internal fastcc noundef float | |
| 165 | // release-SAME: (float %x.0.0.val, float %x.1.0.val) | |
| 164 | // release-NEXT: define internal noundef float | |
| 165 | // release-SAME: (ptr {{.*}}%x.0, ptr {{.*}}%x.1) | |
| 166 | 166 | #[autodiff_forward(df7, Dual, Dual)] |
| 167 | 167 | #[inline(never)] |
| 168 | 168 | fn f7(x: (&f32, &f32)) -> f32 { |
tests/codegen-llvm/autodiff/autodiffv2.rs+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 | // |
tests/codegen-llvm/autodiff/batched.rs+19-13| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT,NoPostopt -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 | |
| ... | ... | @@ -20,22 +20,28 @@ fn square(x: &f32) -> f32 { |
| 20 | 20 | x * x |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | // The base ("scalar") case d_square3, without batching. | |
| 24 | // CHECK: define internal fastcc float @fwddiffesquare(float %x.0.val, float %"x'.0.val") | |
| 25 | // CHECK: %0 = fadd fast float %"x'.0.val", %"x'.0.val" | |
| 26 | // CHECK-NEXT: %1 = fmul fast float %0, %x.0.val | |
| 27 | // CHECK-NEXT: ret float %1 | |
| 28 | // CHECK-NEXT: } | |
| 29 | ||
| 30 | // d_square2 | |
| 31 | // CHECK: define internal fastcc [4 x float] @fwddiffe4square(float %x.0.val, [4 x ptr] %"x'") | |
| 32 | // CHECK: ret [4 x float] | |
| 23 | // CHECK: ; batched::d_square2 | |
| 24 | // CHECK: define internal fastcc void | |
| 25 | // CHECK-SAME: (ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}}) | |
| 26 | // CHECK: ret void | |
| 33 | 27 | // CHECK-NEXT: } |
| 34 | 28 | |
| 35 | // CHECK: define internal fastcc { float, [4 x float] } @fwddiffe4square.{{.*}}(float %x.0.val, [4 x ptr] %"x'") | |
| 36 | // CHECK: ret { float, [4 x float] } | |
| 29 | // CHECK: ; batched::d_square1 | |
| 30 | // CHECK: define internal fastcc void | |
| 31 | // CHECK-SAME: (ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}}) | |
| 32 | // CHECK: ret void | |
| 37 | 33 | // CHECK-NEXT: } |
| 38 | 34 | |
| 35 | // The base ("scalar") case d_square3, without batching. | |
| 36 | // CHECK: define internal float @fwddiffesquare(ptr {{.*}}, ptr {{.*}}) | |
| 37 | // CHECK: [[SHADOW_X:%"_[0-9]+'ipl"]] = load float, ptr %"x'" | |
| 38 | // CHECK-NEXT: [[PRIMAL_X:%_[0-9]+]] = load float, ptr %x | |
| 39 | // CHECK-NEXT: [[MUL1:%[0-9]+]] = fmul fast float [[SHADOW_X]], [[PRIMAL_X]] | |
| 40 | // CHECK-NEXT: [[MUL2:%[0-9]+]] = fmul fast float [[SHADOW_X]], [[PRIMAL_X]] | |
| 41 | // CHECK-NEXT: [[ADD1:%[0-9]+]] = fadd fast float [[MUL1]], [[MUL2]] | |
| 42 | // CHECK-NEXT: ret float [[ADD1]] | |
| 43 | // CHECK-NEXT: } | |
| 44 | ||
| 39 | 45 | fn main() { |
| 40 | 46 | let x = std::hint::black_box(3.0); |
| 41 | 47 | let output = square(&x); |
tests/codegen-llvm/autodiff/generic.rs+2-2| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 | //@ revisions: F32 F64 Main |
| ... | ... | @@ -34,7 +34,7 @@ fn square<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T { |
| 34 | 34 | // F64-NEXT: ; Function Attrs: {{.*}} |
| 35 | 35 | // F64-NEXT: define internal {{.*}} void |
| 36 | 36 | // F64-NEXT: start: |
| 37 | // F64-NEXT: {{(tail )?}}call {{(fastcc )?}}void @diffe_{{.*}}(double {{.*}}, ptr {{.*}}) | |
| 37 | // F64-NEXT: {{(tail )?}}call fast { double } @diffe_{{.*}}(ptr {{.*}}, ptr {{.*}}, double {{.*}}) | |
| 38 | 38 | // F64-NEXT: ret void |
| 39 | 39 | |
| 40 | 40 | // Main-LABEL: ; generic::main |
tests/codegen-llvm/autodiff/identical_fnc.rs+3-3| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff_post_passes=mergefunc,function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 | // |
| ... | ... | @@ -32,9 +32,9 @@ fn square2(x: &f64) -> f64 { |
| 32 | 32 | // CHECK-NOT:br |
| 33 | 33 | // CHECK-NOT:ret |
| 34 | 34 | // CHECK:; call identical_fnc::d_square |
| 35 | // CHECK-NEXT:call fastcc void @[[HASH:.+]](double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx1) | |
| 35 | // CHECK-NEXT:call fastcc void @[[HASH:.+]](ptr {{.*}}, ptr {{.*}}) | |
| 36 | 36 | // CHECK:; call identical_fnc::d_square |
| 37 | // CHECK-NEXT:call fastcc void @[[HASH]](double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx2) | |
| 37 | // CHECK-NEXT:call fastcc void @[[HASH]](ptr {{.*}}, ptr {{.*}}) | |
| 38 | 38 | |
| 39 | 39 | fn main() { |
| 40 | 40 | let x = std::hint::black_box(3.0); |
tests/codegen-llvm/autodiff/impl.rs+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 |
tests/codegen-llvm/autodiff/scalar.rs+13-9| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 | #![feature(autodiff)] |
| ... | ... | @@ -12,14 +12,18 @@ fn square(x: &f64) -> f64 { |
| 12 | 12 | x * x |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | // CHECK:define internal fastcc double @diffesquare(double %x.0.val, ptr nonnull align 8 captures(none) %"x'") | |
| 16 | // CHECK-NEXT:invertstart: | |
| 17 | // CHECK-NEXT: %_0 = fmul double %x.0.val, %x.0.val | |
| 18 | // CHECK-NEXT: %0 = fadd fast double %x.0.val, %x.0.val | |
| 19 | // CHECK-NEXT: %1 = load double, ptr %"x'", align 8 | |
| 20 | // CHECK-NEXT: %2 = fadd fast double %1, %0 | |
| 21 | // CHECK-NEXT: store double %2, ptr %"x'", align 8 | |
| 22 | // CHECK-NEXT: ret double %_0 | |
| 15 | // CHECK:define internal { double } @diffesquare(ptr {{.*}}, ptr {{.*}}, double {{.*}}) | |
| 16 | // CHECK-NEXT:start: | |
| 17 | // CHECK-NEXT: [[X:%_[0-9]+]] = load double, ptr %x, align 8 | |
| 18 | // CHECK-NEXT: [[SQUARE:%_[0-9]+]] = fmul double [[X]], [[X]] | |
| 19 | // CHECK-NEXT: [[DIFFR1:%[0-9]+]] = fmul fast double %differeturn, [[X]] | |
| 20 | // CHECK-NEXT: [[DIFFR2:%[0-9]+]] = fmul fast double %differeturn, [[X]] | |
| 21 | // CHECK-NEXT: [[ADD1:%[0-9]+]] = fadd fast double [[DIFFR1]], [[DIFFR2]] | |
| 22 | // CHECK-NEXT: [[SHADOW_X:%[0-9]+]] = load double, ptr %"x'", align 8 | |
| 23 | // CHECK-NEXT: [[ADD2:%[0-9]+]] = fadd fast double [[SHADOW_X]], [[ADD1]] | |
| 24 | // CHECK-NEXT: store double [[ADD2]], ptr %"x'", align 8 | |
| 25 | // CHECK-NEXT: [[RET:%[0-9]+]] = insertvalue { double } undef, double [[SQUARE]], 0 | |
| 26 | // CHECK-NEXT: ret { double } [[RET]] | |
| 23 | 27 | // CHECK-NEXT:} |
| 24 | 28 | |
| 25 | 29 | fn main() { |
tests/codegen-llvm/autodiff/sret.rs+13-9| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 | |
| ... | ... | @@ -18,17 +18,21 @@ fn primal(x: f32, y: f32) -> f64 { |
| 18 | 18 | (x * x * y) as f64 |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | // CHECK: define internal fastcc { double, float, float } @diffeprimal(float noundef %x, float noundef %y) | |
| 22 | // CHECK-NEXT: invertstart: | |
| 21 | // CHECK: define internal { double, float, float } @diffeprimal(float noundef %x, float noundef %y, double %differeturn) | |
| 22 | // CHECK-NEXT: start: | |
| 23 | 23 | // CHECK-NEXT: %_4 = fmul float %x, %x |
| 24 | 24 | // CHECK-NEXT: %_3 = fmul float %_4, %y |
| 25 | 25 | // CHECK-NEXT: %_0 = fpext float %_3 to double |
| 26 | // CHECK-NEXT: %0 = fadd fast float %y, %y | |
| 27 | // CHECK-NEXT: %1 = fmul fast float %0, %x | |
| 28 | // CHECK-NEXT: %2 = insertvalue { double, float, float } undef, double %_0, 0 | |
| 29 | // CHECK-NEXT: %3 = insertvalue { double, float, float } %2, float %1, 1 | |
| 30 | // CHECK-NEXT: %4 = insertvalue { double, float, float } %3, float %_4, 2 | |
| 31 | // CHECK-NEXT: ret { double, float, float } %4 | |
| 26 | // CHECK-NEXT: %0 = fptrunc fast double %differeturn to float | |
| 27 | // CHECK-NEXT: %1 = fmul fast float %0, %y | |
| 28 | // CHECK-NEXT: %2 = fmul fast float %0, %_4 | |
| 29 | // CHECK-NEXT: %3 = fmul fast float %1, %x | |
| 30 | // CHECK-NEXT: %4 = fmul fast float %1, %x | |
| 31 | // CHECK-NEXT: %5 = fadd fast float %3, %4 | |
| 32 | // CHECK-NEXT: %6 = insertvalue { double, float, float } undef, double %_0, 0 | |
| 33 | // CHECK-NEXT: %7 = insertvalue { double, float, float } %6, float %5, 1 | |
| 34 | // CHECK-NEXT: %8 = insertvalue { double, float, float } %7, float %2, 2 | |
| 35 | // CHECK-NEXT: ret { double, float, float } %8 | |
| 32 | 36 | // CHECK-NEXT: } |
| 33 | 37 | |
| 34 | 38 | fn main() { |
tests/codegen-llvm/autodiff/trait.rs+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 |
tests/codegen-llvm/autodiff/typetree.rs+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 |
tests/codegen-llvm/autodiff/void_ret.rs+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT,NoPostopt -C no-prepopulate-passes -C opt-level=3 -Clto=fat | |
| 1 | //@ compile-flags: -Zautodiff=Enable,NoTT -Zautodiff_post_passes=function(mem2reg,instsimplify,simplifycfg) -C no-prepopulate-passes -C opt-level=3 -Clto=fat | |
| 2 | 2 | //@ no-prefer-dynamic |
| 3 | 3 | //@ needs-enzyme |
| 4 | 4 |
tests/codegen-llvm/lib-optimizations/transmute_copy.rs created+65| ... | ... | @@ -0,0 +1,65 @@ |
| 1 | //@ compile-flags: -Copt-level=1 | |
| 2 | //@ only-64bit | |
| 3 | ||
| 4 | #![crate_type = "lib"] | |
| 5 | ||
| 6 | // Check that we don't have runtime alignment checks, just a safe alignment. | |
| 7 | // (Rust emits a branch, but LLVM merges the loads from the arms.) | |
| 8 | ||
| 9 | use std::mem::transmute_copy; | |
| 10 | ||
| 11 | // CHECK-LABEL: @transmute_copy_i16_from_i32_slice | |
| 12 | // CHECK-SAME: ptr{{.+}}%_0, | |
| 13 | // CHECK-SAME: ptr{{.+}}%x.0, | |
| 14 | // CHECK-SAME: i64{{.+}}%x.1) | |
| 15 | #[no_mangle] | |
| 16 | pub unsafe fn transmute_copy_i16_from_i32_slice(x: &[i32]) -> [i16; 7] { | |
| 17 | // CHECK: start: | |
| 18 | // CHECK-NEXT: @llvm.memcpy | |
| 19 | // CHECK-SAME: align 2{{.+}}%_0, | |
| 20 | // CHECK-SAME: align 4{{.+}}%x.0, | |
| 21 | // CHECK-SAME: i64 14, | |
| 22 | // CHECK-NEXT: ret void | |
| 23 | transmute_copy(x) | |
| 24 | } | |
| 25 | ||
| 26 | // CHECK-LABEL: @transmute_copy_i32_from_i16_slice | |
| 27 | // CHECK-SAME: ptr{{.+}}%_0, | |
| 28 | // CHECK-SAME: ptr{{.+}}%x.0, | |
| 29 | // CHECK-SAME: i64{{.+}}%x.1) | |
| 30 | #[no_mangle] | |
| 31 | pub unsafe fn transmute_copy_i32_from_i16_slice(x: &[i16]) -> [i32; 3] { | |
| 32 | // CHECK: start: | |
| 33 | // CHECK-NEXT: @llvm.memcpy | |
| 34 | // CHECK-SAME: align 4{{.+}}%_0, | |
| 35 | // CHECK-SAME: align 2{{.+}}%x.0, | |
| 36 | // CHECK-SAME: i64 12, | |
| 37 | // CHECK-NEXT: ret void | |
| 38 | transmute_copy(x) | |
| 39 | } | |
| 40 | ||
| 41 | // CHECK-LABEL: i32 @transmute_copy_i32_from_dyn | |
| 42 | // CHECK-SAME: ptr{{.+}}%x.0, | |
| 43 | // CHECK-SAME: ptr{{.+}}%x.1) | |
| 44 | #[no_mangle] | |
| 45 | pub unsafe fn transmute_copy_i32_from_dyn(x: &dyn std::fmt::Debug) -> i32 { | |
| 46 | // CHECK: start: | |
| 47 | // CHECK-NEXT: [[TEMP:%.+]] = load i32, ptr %x.0, align 1 | |
| 48 | // CHECK-NEXT: ret i32 [[TEMP]] | |
| 49 | transmute_copy(x) | |
| 50 | } | |
| 51 | ||
| 52 | // CHECK-LABEL: @transmute_copy_i16_array_from_dyn | |
| 53 | // CHECK-SAME: ptr{{.+}}%_0, | |
| 54 | // CHECK-SAME: ptr{{.+}}%x.0, | |
| 55 | // CHECK-SAME: ptr{{.+}}%x.1) | |
| 56 | #[no_mangle] | |
| 57 | pub unsafe fn transmute_copy_i16_array_from_dyn(x: &dyn std::fmt::Debug) -> [i16; 7] { | |
| 58 | // CHECK: start: | |
| 59 | // CHECK-NEXT: @llvm.memcpy | |
| 60 | // CHECK-SAME: align 2{{.+}}%_0, | |
| 61 | // CHECK-SAME: align 1{{.+}}%x.0, | |
| 62 | // CHECK-SAME: i64 14, | |
| 63 | // CHECK-NEXT: ret void | |
| 64 | transmute_copy(x) | |
| 65 | } |
tests/rustdoc-html/reexport/auxiliary/glob-import.rs created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | pub extern crate std as wgc; |
tests/rustdoc-html/reexport/glob-import.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | // This test ensures that inlining a foreign crate through a glob import doesn't | |
| 2 | // panic (because we're trying to retrieve attributes from an item which doesn't | |
| 3 | // have attributes). | |
| 4 | // Regression test for <https://github.com/rust-lang/rust/issues/158686>. | |
| 5 | ||
| 6 | //@ aux-build: glob-import.rs | |
| 7 | ||
| 8 | #![crate_name = "foo"] | |
| 9 | ||
| 10 | extern crate glob_import; | |
| 11 | ||
| 12 | //@ has 'foo/index.html' | |
| 13 | // There should be only one item listed: `wgc` (the only `glob-import` dep public item). | |
| 14 | //@ count - '//*[@id="main-content"]/h2[@class="section-header"]' 1 | |
| 15 | //@ count - '//*[@id="main-content"]/dl[@class="item-table"]/dt' 1 | |
| 16 | ||
| 17 | pub use glob_import::*; |
tests/ui/iterators/into-iter-on-arrays-2018.rs+2-3| ... | ... | @@ -5,6 +5,7 @@ use std::array::IntoIter; |
| 5 | 5 | use std::ops::Deref; |
| 6 | 6 | use std::rc::Rc; |
| 7 | 7 | use std::slice::Iter; |
| 8 | use std::boxed::BoxedArrayIntoIter; | |
| 8 | 9 | |
| 9 | 10 | fn main() { |
| 10 | 11 | let array = [0; 10]; |
| ... | ... | @@ -15,9 +16,7 @@ fn main() { |
| 15 | 16 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` |
| 16 | 17 | //~| WARNING this changes meaning |
| 17 | 18 | |
| 18 | let _: Iter<'_, i32> = Box::new(array).into_iter(); | |
| 19 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 20 | //~| WARNING this changes meaning | |
| 19 | let _: BoxedArrayIntoIter<i32, 10> = Box::new(array).into_iter(); | |
| 21 | 20 | |
| 22 | 21 | let _: Iter<'_, i32> = Rc::new(array).into_iter(); |
| 23 | 22 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` |
tests/ui/iterators/into-iter-on-arrays-2018.stderr+5-14| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 |
| 2 | --> $DIR/into-iter-on-arrays-2018.rs:14:34 | |
| 2 | --> $DIR/into-iter-on-arrays-2018.rs:15:34 | |
| 3 | 3 | | |
| 4 | 4 | LL | let _: Iter<'_, i32> = array.into_iter(); |
| 5 | 5 | | ^^^^^^^^^ |
| ... | ... | @@ -19,16 +19,7 @@ LL + let _: Iter<'_, i32> = IntoIterator::into_iter(array); |
| 19 | 19 | | |
| 20 | 20 | |
| 21 | 21 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 |
| 22 | --> $DIR/into-iter-on-arrays-2018.rs:18:44 | |
| 23 | | | |
| 24 | LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); | |
| 25 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 26 | | | |
| 27 | = warning: this changes meaning in Rust 2021 | |
| 28 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 29 | ||
| 30 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 31 | --> $DIR/into-iter-on-arrays-2018.rs:22:43 | |
| 22 | --> $DIR/into-iter-on-arrays-2018.rs:21:43 | |
| 32 | 23 | | |
| 33 | 24 | LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); |
| 34 | 25 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` |
| ... | ... | @@ -37,7 +28,7 @@ LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); |
| 37 | 28 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> |
| 38 | 29 | |
| 39 | 30 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 |
| 40 | --> $DIR/into-iter-on-arrays-2018.rs:25:41 | |
| 31 | --> $DIR/into-iter-on-arrays-2018.rs:24:41 | |
| 41 | 32 | | |
| 42 | 33 | LL | let _: Iter<'_, i32> = Array(array).into_iter(); |
| 43 | 34 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` |
| ... | ... | @@ -46,7 +37,7 @@ LL | let _: Iter<'_, i32> = Array(array).into_iter(); |
| 46 | 37 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> |
| 47 | 38 | |
| 48 | 39 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 |
| 49 | --> $DIR/into-iter-on-arrays-2018.rs:32:24 | |
| 40 | --> $DIR/into-iter-on-arrays-2018.rs:31:24 | |
| 50 | 41 | | |
| 51 | 42 | LL | for _ in [1, 2, 3].into_iter() {} |
| 52 | 43 | | ^^^^^^^^^ |
| ... | ... | @@ -64,5 +55,5 @@ LL - for _ in [1, 2, 3].into_iter() {} |
| 64 | 55 | LL + for _ in [1, 2, 3] {} |
| 65 | 56 | | |
| 66 | 57 | |
| 67 | warning: 5 warnings emitted | |
| 58 | warning: 4 warnings emitted | |
| 68 | 59 |
tests/ui/iterators/into-iter-on-arrays-2021.rs+2-1| ... | ... | @@ -4,13 +4,14 @@ |
| 4 | 4 | use std::array::IntoIter; |
| 5 | 5 | use std::ops::Deref; |
| 6 | 6 | use std::rc::Rc; |
| 7 | use std::boxed::BoxedArrayIntoIter; | |
| 7 | 8 | |
| 8 | 9 | fn main() { |
| 9 | 10 | let array = [0; 10]; |
| 10 | 11 | |
| 11 | 12 | // In 2021, the method dispatches to `IntoIterator for [T; N]`. |
| 12 | 13 | let _: IntoIter<i32, 10> = array.into_iter(); |
| 13 | let _: IntoIter<i32, 10> = Box::new(array).into_iter(); | |
| 14 | let _: BoxedArrayIntoIter<i32, 10> = Box::new(array).into_iter(); | |
| 14 | 15 | |
| 15 | 16 | // The `array_into_iter` lint doesn't cover other wrappers that deref to an array. |
| 16 | 17 | let _: IntoIter<i32, 10> = Rc::new(array).into_iter(); |
tests/ui/iterators/into-iter-on-arrays-lint.fixed+8-24| ... | ... | @@ -22,31 +22,15 @@ fn main() { |
| 22 | 22 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` |
| 23 | 23 | //~| WARNING this changes meaning |
| 24 | 24 | |
| 25 | Box::new(small).iter(); | |
| 26 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 27 | //~| WARNING this changes meaning | |
| 28 | Box::new([1, 2]).iter(); | |
| 29 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 30 | //~| WARNING this changes meaning | |
| 31 | Box::new(big).iter(); | |
| 32 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 33 | //~| WARNING this changes meaning | |
| 34 | Box::new([0u8; 33]).iter(); | |
| 35 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 36 | //~| WARNING this changes meaning | |
| 25 | Box::new(small).into_iter(); | |
| 26 | Box::new([1, 2]).into_iter(); | |
| 27 | Box::new(big).into_iter(); | |
| 28 | Box::new([0u8; 33]).into_iter(); | |
| 37 | 29 | |
| 38 | Box::new(Box::new(small)).iter(); | |
| 39 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 40 | //~| WARNING this changes meaning | |
| 41 | Box::new(Box::new([1, 2])).iter(); | |
| 42 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 43 | //~| WARNING this changes meaning | |
| 44 | Box::new(Box::new(big)).iter(); | |
| 45 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 46 | //~| WARNING this changes meaning | |
| 47 | Box::new(Box::new([0u8; 33])).iter(); | |
| 48 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 49 | //~| WARNING this changes meaning | |
| 30 | Box::new(Box::new(small)).into_iter(); | |
| 31 | Box::new(Box::new([1, 2])).into_iter(); | |
| 32 | Box::new(Box::new(big)).into_iter(); | |
| 33 | Box::new(Box::new([0u8; 33])).into_iter(); | |
| 50 | 34 | |
| 51 | 35 | // Expressions that should not |
| 52 | 36 | (&[1, 2]).into_iter(); |
tests/ui/iterators/into-iter-on-arrays-lint.rs-16| ... | ... | @@ -23,30 +23,14 @@ fn main() { |
| 23 | 23 | //~| WARNING this changes meaning |
| 24 | 24 | |
| 25 | 25 | Box::new(small).into_iter(); |
| 26 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 27 | //~| WARNING this changes meaning | |
| 28 | 26 | Box::new([1, 2]).into_iter(); |
| 29 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 30 | //~| WARNING this changes meaning | |
| 31 | 27 | Box::new(big).into_iter(); |
| 32 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 33 | //~| WARNING this changes meaning | |
| 34 | 28 | Box::new([0u8; 33]).into_iter(); |
| 35 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 36 | //~| WARNING this changes meaning | |
| 37 | 29 | |
| 38 | 30 | Box::new(Box::new(small)).into_iter(); |
| 39 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 40 | //~| WARNING this changes meaning | |
| 41 | 31 | Box::new(Box::new([1, 2])).into_iter(); |
| 42 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 43 | //~| WARNING this changes meaning | |
| 44 | 32 | Box::new(Box::new(big)).into_iter(); |
| 45 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 46 | //~| WARNING this changes meaning | |
| 47 | 33 | Box::new(Box::new([0u8; 33])).into_iter(); |
| 48 | //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` | |
| 49 | //~| WARNING this changes meaning | |
| 50 | 34 | |
| 51 | 35 | // Expressions that should not |
| 52 | 36 | (&[1, 2]).into_iter(); |
tests/ui/iterators/into-iter-on-arrays-lint.stderr+1-73| ... | ... | @@ -75,77 +75,5 @@ LL - [0u8; 33].into_iter(); |
| 75 | 75 | LL + IntoIterator::into_iter([0u8; 33]); |
| 76 | 76 | | |
| 77 | 77 | |
| 78 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 79 | --> $DIR/into-iter-on-arrays-lint.rs:25:21 | |
| 80 | | | |
| 81 | LL | Box::new(small).into_iter(); | |
| 82 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 83 | | | |
| 84 | = warning: this changes meaning in Rust 2021 | |
| 85 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 86 | ||
| 87 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 88 | --> $DIR/into-iter-on-arrays-lint.rs:28:22 | |
| 89 | | | |
| 90 | LL | Box::new([1, 2]).into_iter(); | |
| 91 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 92 | | | |
| 93 | = warning: this changes meaning in Rust 2021 | |
| 94 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 95 | ||
| 96 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 97 | --> $DIR/into-iter-on-arrays-lint.rs:31:19 | |
| 98 | | | |
| 99 | LL | Box::new(big).into_iter(); | |
| 100 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 101 | | | |
| 102 | = warning: this changes meaning in Rust 2021 | |
| 103 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 104 | ||
| 105 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 106 | --> $DIR/into-iter-on-arrays-lint.rs:34:25 | |
| 107 | | | |
| 108 | LL | Box::new([0u8; 33]).into_iter(); | |
| 109 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 110 | | | |
| 111 | = warning: this changes meaning in Rust 2021 | |
| 112 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 113 | ||
| 114 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 115 | --> $DIR/into-iter-on-arrays-lint.rs:38:31 | |
| 116 | | | |
| 117 | LL | Box::new(Box::new(small)).into_iter(); | |
| 118 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 119 | | | |
| 120 | = warning: this changes meaning in Rust 2021 | |
| 121 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 122 | ||
| 123 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 124 | --> $DIR/into-iter-on-arrays-lint.rs:41:32 | |
| 125 | | | |
| 126 | LL | Box::new(Box::new([1, 2])).into_iter(); | |
| 127 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 128 | | | |
| 129 | = warning: this changes meaning in Rust 2021 | |
| 130 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 131 | ||
| 132 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 133 | --> $DIR/into-iter-on-arrays-lint.rs:44:29 | |
| 134 | | | |
| 135 | LL | Box::new(Box::new(big)).into_iter(); | |
| 136 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 137 | | | |
| 138 | = warning: this changes meaning in Rust 2021 | |
| 139 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 140 | ||
| 141 | warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 | |
| 142 | --> $DIR/into-iter-on-arrays-lint.rs:47:35 | |
| 143 | | | |
| 144 | LL | Box::new(Box::new([0u8; 33])).into_iter(); | |
| 145 | | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | |
| 146 | | | |
| 147 | = warning: this changes meaning in Rust 2021 | |
| 148 | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html> | |
| 149 | ||
| 150 | warning: 12 warnings emitted | |
| 78 | warning: 4 warnings emitted | |
| 151 | 79 |
tests/ui/lazy-type-alias/auto-trait-impls.rs created+53| ... | ... | @@ -0,0 +1,53 @@ |
| 1 | //! Auto-trait impls whose self type is a free (lazy) type alias are checked against the | |
| 2 | //! type the alias *expands* to, not the alias itself. An alias resolving to an otherwise | |
| 3 | //! valid nominal type is accepted, just as if the underlying type had been written | |
| 4 | //! directly; an alias resolving to a problematic type is still rejected. | |
| 5 | //! | |
| 6 | //! Regression test for <https://github.com/rust-lang/rust/issues/157756>. | |
| 7 | ||
| 8 | #![feature(lazy_type_alias, auto_traits, negative_impls)] | |
| 9 | #![allow(incomplete_features)] | |
| 10 | ||
| 11 | struct Local; | |
| 12 | ||
| 13 | auto trait Marker {} | |
| 14 | ||
| 15 | // Aliases expanding to a local nominal type are accepted for both a cross-crate auto trait | |
| 16 | // (`Sync`) and a local one (`Marker`), exactly as if `Local` had been named directly. | |
| 17 | type ToLocal = Local; | |
| 18 | unsafe impl Sync for ToLocal {} | |
| 19 | impl Marker for ToLocal {} | |
| 20 | ||
| 21 | // Nested aliases are expanded transitively, so an alias chain ending in a local nominal type | |
| 22 | // is accepted as well. | |
| 23 | struct Inner; | |
| 24 | type Mid = Inner; | |
| 25 | type Nested = Mid; | |
| 26 | impl Marker for Nested {} | |
| 27 | ||
| 28 | // A generic alias instantiated with a local nominal type is accepted. | |
| 29 | struct Generic; | |
| 30 | type Id<T> = T; | |
| 31 | impl Marker for Id<Generic> {} | |
| 32 | ||
| 33 | // Negative auto-trait impls go through the same orphan check, so an alias to a local nominal | |
| 34 | // type is accepted for them too. | |
| 35 | struct Negated; | |
| 36 | type ToNeg = Negated; | |
| 37 | impl !Marker for ToNeg {} | |
| 38 | ||
| 39 | // An alias expanding to a reference is still rejected for the cross-crate auto trait. Using | |
| 40 | // `&'static NotSync` (with `NotSync: !Sync`) avoids overlapping std's `Send for &T` impl, so | |
| 41 | // the only error is the auto-trait nominal-type restriction. | |
| 42 | struct NotSync; | |
| 43 | impl !Sync for NotSync {} | |
| 44 | type ToRef = &'static NotSync; | |
| 45 | unsafe impl Send for ToRef {} | |
| 46 | //~^ ERROR cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `&'static NotSync` | |
| 47 | ||
| 48 | // An alias expanding to a trait object is still rejected for the local auto trait. | |
| 49 | type ToDyn = dyn Send; | |
| 50 | impl Marker for ToDyn {} | |
| 51 | //~^ ERROR traits with a default impl, like `Marker`, cannot be implemented for trait object `(dyn Send + 'static)` | |
| 52 | ||
| 53 | fn main() {} |
tests/ui/lazy-type-alias/auto-trait-impls.stderr created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | error[E0321]: traits with a default impl, like `Marker`, cannot be implemented for trait object `(dyn Send + 'static)` | |
| 2 | --> $DIR/auto-trait-impls.rs:50:1 | |
| 3 | | | |
| 4 | LL | impl Marker for ToDyn {} | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: a trait object implements `Marker` if and only if `Marker` is one of the trait object's trait bounds | |
| 8 | ||
| 9 | error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `&'static NotSync` | |
| 10 | --> $DIR/auto-trait-impls.rs:45:1 | |
| 11 | | | |
| 12 | LL | unsafe impl Send for ToRef {} | |
| 13 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type | |
| 14 | ||
| 15 | error: aborting due to 2 previous errors | |
| 16 | ||
| 17 | For more information about this error, try `rustc --explain E0321`. |
tests/ui/precondition-checks/transmute_copy.rs created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | //@ run-crash | |
| 2 | //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes | |
| 3 | //@ error-pattern: unsafe precondition(s) violated: cannot transmute_copy if Dst is larger than Src | |
| 4 | ||
| 5 | fn main() { | |
| 6 | unsafe { | |
| 7 | let _unused: u64 = std::mem::transmute_copy(&1_u8); | |
| 8 | } | |
| 9 | } |
tests/ui/proc-macro/attributes-on-modules-fail.rs-27| ... | ... | @@ -17,31 +17,4 @@ type A = X; //~ ERROR cannot find type `X` in this scope |
| 17 | 17 | #[derive(Copy)] //~ ERROR `derive` may only be applied to `struct`s, `enum`s and `union`s |
| 18 | 18 | mod n {} |
| 19 | 19 | |
| 20 | #[empty_attr] | |
| 21 | mod module; //~ ERROR file modules in proc macro input are unstable | |
| 22 | ||
| 23 | #[empty_attr] | |
| 24 | mod outer { | |
| 25 | mod inner; //~ ERROR file modules in proc macro input are unstable | |
| 26 | ||
| 27 | mod inner_inline {} // OK | |
| 28 | } | |
| 29 | ||
| 30 | #[derive(Empty)] | |
| 31 | struct S { | |
| 32 | field: [u8; { | |
| 33 | #[path = "outer/inner.rs"] | |
| 34 | mod inner; //~ ERROR file modules in proc macro input are unstable | |
| 35 | mod inner_inline {} // OK | |
| 36 | 0 | |
| 37 | }], | |
| 38 | } | |
| 39 | ||
| 40 | #[identity_attr] | |
| 41 | fn f() { | |
| 42 | #[path = "outer/inner.rs"] | |
| 43 | mod inner; //~ ERROR file modules in proc macro input are unstable | |
| 44 | mod inner_inline {} // OK | |
| 45 | } | |
| 46 | ||
| 47 | 20 | fn main() {} |
tests/ui/proc-macro/attributes-on-modules-fail.stderr+2-42| ... | ... | @@ -6,46 +6,6 @@ LL | #[derive(Copy)] |
| 6 | 6 | LL | mod n {} |
| 7 | 7 | | -------- not a `struct`, `enum` or `union` |
| 8 | 8 | |
| 9 | error[E0658]: file modules in proc macro input are unstable | |
| 10 | --> $DIR/attributes-on-modules-fail.rs:21:1 | |
| 11 | | | |
| 12 | LL | mod module; | |
| 13 | | ^^^^^^^^^^^ | |
| 14 | | | |
| 15 | = note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information | |
| 16 | = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable | |
| 17 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date | |
| 18 | ||
| 19 | error[E0658]: file modules in proc macro input are unstable | |
| 20 | --> $DIR/attributes-on-modules-fail.rs:25:5 | |
| 21 | | | |
| 22 | LL | mod inner; | |
| 23 | | ^^^^^^^^^^ | |
| 24 | | | |
| 25 | = note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information | |
| 26 | = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable | |
| 27 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date | |
| 28 | ||
| 29 | error[E0658]: file modules in proc macro input are unstable | |
| 30 | --> $DIR/attributes-on-modules-fail.rs:34:9 | |
| 31 | | | |
| 32 | LL | mod inner; | |
| 33 | | ^^^^^^^^^^ | |
| 34 | | | |
| 35 | = note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information | |
| 36 | = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable | |
| 37 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date | |
| 38 | ||
| 39 | error[E0658]: file modules in proc macro input are unstable | |
| 40 | --> $DIR/attributes-on-modules-fail.rs:43:5 | |
| 41 | | | |
| 42 | LL | mod inner; | |
| 43 | | ^^^^^^^^^^ | |
| 44 | | | |
| 45 | = note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information | |
| 46 | = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable | |
| 47 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date | |
| 48 | ||
| 49 | 9 | error[E0425]: cannot find type `Y` in this scope |
| 50 | 10 | --> $DIR/attributes-on-modules-fail.rs:11:14 |
| 51 | 11 | | |
| ... | ... | @@ -68,7 +28,7 @@ help: consider importing this struct |
| 68 | 28 | LL + use m::X; |
| 69 | 29 | | |
| 70 | 30 | |
| 71 | error: aborting due to 7 previous errors | |
| 31 | error: aborting due to 3 previous errors | |
| 72 | 32 | |
| 73 | Some errors have detailed explanations: E0425, E0658, E0774. | |
| 33 | Some errors have detailed explanations: E0425, E0774. | |
| 74 | 34 | For more information about an error, try `rustc --explain E0425`. |
tests/ui/proc-macro/auxiliary/expect-modules.rs created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | /// Macros that assert that certain `mod` items are present in their input. | |
| 2 | ||
| 3 | extern crate proc_macro; | |
| 4 | ||
| 5 | use proc_macro::TokenStream; | |
| 6 | ||
| 7 | #[proc_macro_attribute] | |
| 8 | pub fn expect_mod_item(_attrs: TokenStream, item: TokenStream) -> TokenStream { | |
| 9 | let s = item.to_string(); | |
| 10 | ||
| 11 | assert_eq!(s, "mod module;"); | |
| 12 | ||
| 13 | item | |
| 14 | } | |
| 15 | ||
| 16 | #[proc_macro_attribute] | |
| 17 | pub fn expect_mods_attr(_attrs: TokenStream, item: TokenStream) -> TokenStream { | |
| 18 | let s = item.to_string(); | |
| 19 | ||
| 20 | assert_contains(&s, "mod attr_outlined;"); | |
| 21 | assert_contains(&s, "mod attr_inline {}"); | |
| 22 | ||
| 23 | item | |
| 24 | } | |
| 25 | ||
| 26 | #[proc_macro_derive(ExpectModsDerive)] | |
| 27 | pub fn expect_mods_derive(item: TokenStream) -> TokenStream { | |
| 28 | let s = item.to_string(); | |
| 29 | ||
| 30 | assert_contains(&s, "mod derive_outlined;"); | |
| 31 | assert_contains(&s, "mod derive_inline {}"); | |
| 32 | ||
| 33 | TokenStream::new() | |
| 34 | } | |
| 35 | ||
| 36 | #[track_caller] | |
| 37 | fn assert_contains(s: &str, needle: &str) { | |
| 38 | if !s.contains(needle) { | |
| 39 | panic!("{needle:?} not found in:\n---\n{s}\n---\n"); | |
| 40 | } | |
| 41 | } |
tests/ui/proc-macro/inner-attr-file-mod.rs+1-2| ... | ... | @@ -9,8 +9,7 @@ extern crate test_macros; |
| 9 | 9 | |
| 10 | 10 | #[deny(unused_attributes)] |
| 11 | 11 | mod module_with_attrs; |
| 12 | //~^ ERROR file modules in proc macro input are unstable | |
| 13 | //~| ERROR custom inner attributes are unstable | |
| 12 | //~^ ERROR custom inner attributes are unstable | |
| 14 | 13 | |
| 15 | 14 | fn main() {} |
| 16 | 15 |
tests/ui/proc-macro/inner-attr-file-mod.stderr+1-11| ... | ... | @@ -18,16 +18,6 @@ LL | #![print_attr] |
| 18 | 18 | = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable |
| 19 | 19 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 20 | 20 | |
| 21 | error[E0658]: file modules in proc macro input are unstable | |
| 22 | --> $DIR/inner-attr-file-mod.rs:11:1 | |
| 23 | | | |
| 24 | LL | mod module_with_attrs; | |
| 25 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
| 26 | | | |
| 27 | = note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information | |
| 28 | = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable | |
| 29 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date | |
| 30 | ||
| 31 | 21 | error[E0658]: custom inner attributes are unstable |
| 32 | 22 | --> $DIR/inner-attr-file-mod.rs:11:1 |
| 33 | 23 | | |
| ... | ... | @@ -38,6 +28,6 @@ LL | mod module_with_attrs; |
| 38 | 28 | = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable |
| 39 | 29 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 40 | 30 | |
| 41 | error: aborting due to 4 previous errors | |
| 31 | error: aborting due to 3 previous errors | |
| 42 | 32 | |
| 43 | 33 | For more information about this error, try `rustc --explain E0658`. |
tests/ui/proc-macro/module.rs+4-1| ... | ... | @@ -1 +1,4 @@ |
| 1 | //@ ignore-auxiliary (used by `./attributes-on-modules-fail.rs`) | |
| 1 | //@ ignore-auxiliary (used by `./attributes-on-modules-fail.rs` and `modules-in-input.rs`) | |
| 2 | ||
| 3 | // An item that can be referenced to verify the module has been properly loaded. | |
| 4 | pub const fn hello() {} |
tests/ui/proc-macro/modules-in-input.rs created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | //@ check-pass | |
| 2 | //@ proc-macro: expect-modules.rs | |
| 3 | //@ reference: macro.invocation.attr.mod | |
| 4 | ||
| 5 | // Verifies how module items are represented in proc macro input. | |
| 6 | ||
| 7 | #[macro_use] | |
| 8 | extern crate expect_modules; | |
| 9 | ||
| 10 | #[expect_modules::expect_mod_item] | |
| 11 | mod module; | |
| 12 | ||
| 13 | fn check() { | |
| 14 | module::hello(); | |
| 15 | } | |
| 16 | ||
| 17 | #[expect_modules::expect_mods_attr] | |
| 18 | mod outer { | |
| 19 | #[path = "../module.rs"] | |
| 20 | mod attr_outlined; | |
| 21 | mod attr_inline {} | |
| 22 | ||
| 23 | fn check() { | |
| 24 | attr_outlined::hello(); | |
| 25 | } | |
| 26 | } | |
| 27 | ||
| 28 | #[expect_modules::expect_mods_attr] | |
| 29 | fn foo() { | |
| 30 | #[path = "module.rs"] | |
| 31 | mod attr_outlined; | |
| 32 | mod attr_inline {} | |
| 33 | attr_outlined::hello(); | |
| 34 | } | |
| 35 | ||
| 36 | #[derive(expect_modules::ExpectModsDerive)] | |
| 37 | struct Foo( | |
| 38 | [u8; { | |
| 39 | #[path = "module.rs"] | |
| 40 | mod derive_outlined; | |
| 41 | mod derive_inline {} | |
| 42 | derive_outlined::hello(); | |
| 43 | 0 | |
| 44 | }], | |
| 45 | ); | |
| 46 | ||
| 47 | fn main() {} |
tests/ui/proc-macro/unsafe-mod.rs-2| ... | ... | @@ -1,8 +1,6 @@ |
| 1 | 1 | //@ run-pass |
| 2 | 2 | //@ proc-macro: macro-only-syntax.rs |
| 3 | 3 | |
| 4 | #![feature(proc_macro_hygiene)] | |
| 5 | ||
| 6 | 4 | extern crate macro_only_syntax; |
| 7 | 5 | |
| 8 | 6 | #[macro_only_syntax::expect_unsafe_mod] |
tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs+2-1| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@ check-pass | |
| 2 | ||
| 1 | 3 | #![feature(reborrow)] |
| 2 | 4 | |
| 3 | 5 | use std::marker::{CoerceShared, Reborrow}; |
| ... | ... | @@ -25,7 +27,6 @@ struct AliasRef<'a> { |
| 25 | 27 | } |
| 26 | 28 | |
| 27 | 29 | impl<'a> CoerceShared<AliasRef<'a>> for AliasMut<'a> {} |
| 28 | //~^ ERROR | |
| 29 | 30 | |
| 30 | 31 | struct InnerLifetimeMut<'a> { |
| 31 | 32 | value: &'a mut &'static (), |
tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | error[E0277]: the trait bound `&'a mut u32: CoerceShared<&'a u32>` is not satisfied | |
| 2 | --> $DIR/coerce-shared-mut-ref-field-validation.rs:27:1 | |
| 3 | | | |
| 4 | LL | impl<'a> CoerceShared<AliasRef<'a>> for AliasMut<'a> {} | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `CoerceShared<&'a u32>` is not implemented for `&'a mut u32` | |
| 6 | ||
| 7 | error: aborting due to 1 previous error | |
| 8 | ||
| 9 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/reborrow/coerce-shared-normalize.rs created+56| ... | ... | @@ -0,0 +1,56 @@ |
| 1 | //@ check-pass | |
| 2 | ||
| 3 | // Previously we didn't normalize the source type of `CoerceShared` when | |
| 4 | // checking its trait impls. | |
| 5 | // We also didn't normalize the types of fields in the wrappers. | |
| 6 | // So they fail the trait impl check in `coerce_shared_info` even if | |
| 7 | // the normalized types satisfy the requirements. | |
| 8 | ||
| 9 | #![feature(reborrow)] | |
| 10 | use std::marker::{CoerceShared, Reborrow}; | |
| 11 | ||
| 12 | struct NonParam; | |
| 13 | ||
| 14 | trait HasAssoc<'a> { | |
| 15 | type Assoc; | |
| 16 | } | |
| 17 | ||
| 18 | struct A; | |
| 19 | impl<'a> HasAssoc<'a> for A { | |
| 20 | type Assoc = &'a mut NonParam; | |
| 21 | } | |
| 22 | type MutAlias<'a> = <A as HasAssoc<'a>>::Assoc; | |
| 23 | ||
| 24 | struct B; | |
| 25 | impl<'a> HasAssoc<'a> for B { | |
| 26 | type Assoc = &'a NonParam; | |
| 27 | } | |
| 28 | type RefAlias<'a> = <B as HasAssoc<'a>>::Assoc; | |
| 29 | ||
| 30 | struct CustomMut<'a>(MutAlias<'a>); | |
| 31 | struct CustomRef<'a>(RefAlias<'a>); | |
| 32 | ||
| 33 | struct C; | |
| 34 | impl<'a> HasAssoc<'a> for C { | |
| 35 | type Assoc = CustomMut<'a>; | |
| 36 | } | |
| 37 | type CustomMutAlias<'a> = <C as HasAssoc<'a>>::Assoc; | |
| 38 | ||
| 39 | struct D; | |
| 40 | impl<'a> HasAssoc<'a> for D { | |
| 41 | type Assoc = CustomRef<'a>; | |
| 42 | } | |
| 43 | type CustomRefAlias<'a> = <D as HasAssoc<'a>>::Assoc; | |
| 44 | ||
| 45 | impl<'a> Clone for CustomRef<'a> { | |
| 46 | fn clone(&self) -> Self { | |
| 47 | Self(self.0) | |
| 48 | } | |
| 49 | } | |
| 50 | impl<'a> Copy for CustomRef<'a> {} | |
| 51 | ||
| 52 | ||
| 53 | impl<'a> Reborrow for CustomMut<'a> {} | |
| 54 | impl<'a> CoerceShared<CustomRefAlias<'a>> for CustomMutAlias<'a> {} | |
| 55 | ||
| 56 | fn main() {} |
tests/ui/type-alias-impl-trait/impl_for_weak_alias.rs+5-1| ... | ... | @@ -1,3 +1,8 @@ |
| 1 | //! The orphan check expands a free alias used as the self type of an auto-trait impl, so an | |
| 2 | //! alias resolving to a tuple is accepted just like the tuple written directly. See #157756. | |
| 3 | ||
| 4 | //@ check-pass | |
| 5 | ||
| 1 | 6 | #![feature(type_alias_impl_trait)] |
| 2 | 7 | #![feature(auto_traits)] |
| 3 | 8 | |
| ... | ... | @@ -5,7 +10,6 @@ type Alias = (impl Sized, u8); |
| 5 | 10 | |
| 6 | 11 | auto trait Trait {} |
| 7 | 12 | impl Trait for Alias {} |
| 8 | //~^ ERROR traits with a default impl, like `Trait`, cannot be implemented for type alias `Alias` | |
| 9 | 13 | |
| 10 | 14 | #[define_opaque(Alias)] |
| 11 | 15 | fn _def() -> Alias { |
tests/ui/type-alias-impl-trait/impl_for_weak_alias.stderr deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | error[E0321]: traits with a default impl, like `Trait`, cannot be implemented for type alias `Alias` | |
| 2 | --> $DIR/impl_for_weak_alias.rs:7:1 | |
| 3 | | | |
| 4 | LL | impl Trait for Alias {} | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: a trait object implements `Trait` if and only if `Trait` is one of the trait object's trait bounds | |
| 8 | ||
| 9 | error: aborting due to 1 previous error | |
| 10 | ||
| 11 | For more information about this error, try `rustc --explain E0321`. |