authorbors <bors@rust-lang.org> 2026-07-05 20:37:27 UTC
committerbors <bors@rust-lang.org> 2026-07-05 20:37:27 UTC
log3659db0d3e2cd634c766fcda79ed118eca31a9fd
treeef148ffa7c8fa747f215faefd1547de7cc1d8827
parent1c02d9026c9da54ef3323436f0ed0f8dd091d128
parent9f3f1175689eafcca858199673c0c4943fd2a98b

Auto merge of #158811 - JonathanBrouwer:rollup-Rzb4mH7, r=JonathanBrouwer

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 @@
1Version 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
110Version 1.96.0 (2026-05-28)
211==========================
312
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
39use std::iter;
40use std::ops::ControlFlow;
41
42use ast::visit::Visitor;
43use hir::def::{DefKind, Res};
44use hir::{BodyId, HirId};
45use rustc_abi::ExternAbi;
46use rustc_ast as ast;
47use rustc_ast::node_id::NodeMap;
48use rustc_ast::*;
49use rustc_data_structures::fx::FxHashSet;
50use rustc_hir::attrs::{AttributeKind, InlineAttr};
51use rustc_hir::{self as hir, FnDeclFlags};
52use rustc_middle::span_bug;
53use rustc_middle::ty::{Asyncness, PerOwnerResolverData};
54use rustc_span::def_id::{DefId, LocalDefId};
55use rustc_span::symbol::kw;
56use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
57
58use crate::delegation::generics::{
59 GenericsGenerationResult, GenericsGenerationResults, GenericsPosition,
60};
61use crate::diagnostics::{
62 CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion,
63 DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee,
64};
65use crate::{
66 AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
67};
68
69mod generics;
70
71pub(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
78struct AttrAdditionInfo {
79 pub equals: fn(&hir::Attribute) -> bool,
80 pub kind: AttrAdditionKind,
81}
82
83enum 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)]
90struct 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
101const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
102
103static 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
125impl<'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
850struct SelfResolver<'a, 'b, 'hir> {
851 ctxt: &'a mut LoweringContext<'b, 'hir>,
852 path_id: NodeId,
853 self_param_id: NodeId,
854}
855
856impl 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
867impl<'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 @@
1use rustc_hir::attrs::{AttributeKind, InlineAttr};
2use rustc_hir::{self as hir};
3use rustc_span::Span;
4use rustc_span::def_id::DefId;
5
6use crate::LoweringContext;
7use crate::delegation::DelegationResolution;
8
9struct AdditionInfo {
10 pub equals: fn(&hir::Attribute) -> bool,
11 pub kind: AdditionKind,
12}
13
14enum AdditionKind {
15 Default { factory: fn(Span) -> hir::Attribute },
16 Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
17}
18
19static 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
41impl<'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::*;
44use rustc_data_structures::fx::FxHashSet;
55use rustc_hir as hir;
66use rustc_hir::def_id::DefId;
7use rustc_middle::ty::GenericParamDefKind;
7use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
88use rustc_middle::{bug, ty};
99use rustc_span::symbol::kw;
1010use rustc_span::{Ident, Span, sym};
1111
1212use crate::LoweringContext;
13use crate::delegation::resolution::resolver::DelegationResolver;
1314use crate::diagnostics::DelegationInfersMismatch;
1415
1516#[derive(Debug, Clone, Copy, Eq, PartialEq)]
......@@ -237,74 +238,130 @@ impl<'hir> GenericsGenerationResult<'hir> {
237238 }
238239}
239240
240impl<'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;
241enum 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}
244260
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 }
261struct GenericsResolution<'a, 'tcx> {
262 trait_impl: bool,
257263
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,
271277}
272278
273impl<'hir> LoweringContext<'_, 'hir> {
274 pub(super) fn uplift_delegation_generics(
275 &mut self,
276 delegation: &Delegation,
279impl<'hir> DelegationResolver<'_, 'hir> {
280 fn resolve_generics<'a>(
281 &self,
282 delegation: &'a Delegation,
277283 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()));
280287
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 { .. });
283290
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;
286294
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] = &[];
293296
294 return None;
295 };
297 let qself_is_infer =
298 delegation.qself.as_ref().is_some_and(|qself| qself.ty.is_maybe_parenthesised_infer());
296299
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
301315 };
302316
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);
304361
305362 // If we are in trait impl always generate function whose generics matches
306363 // those that are defined in trait.
307 if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
364 if trait_impl {
308365 // Considering parent generics, during signature inheritance
309366 // we will take those args that are in trait impl header trait ref.
310367 let parent =
......@@ -312,78 +369,65 @@ impl<'hir> LoweringContext<'_, 'hir> {
312369
313370 let parent = GenericsGenerationResult::new(parent);
314371
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
316375 let child = GenericsGenerationResult::new(child);
317376
318377 return GenericsGenerationResults { parent, child, self_ty_propagation_kind: None };
319378 }
320379
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,
355386 &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 }
359399 }
360 } else {
361 DelegationGenerics { data: vec![], pos: GenericsPosition::Parent, trait_impl: false }
362400 };
363401
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());
367407
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 );
370414
371 for synth_param in &sig_params[synth_params_index..] {
415 for synth_param in &sig_child_params[synth_params_index..] {
372416 slots.push(GenericArgSlot::Generate(synth_param, None));
373417 }
374418
375 DelegationGenerics { data: slots, pos: GenericsPosition::Child, trait_impl: false }
419 DelegationGenerics { data: slots, pos: GenericsPosition::Child, trait_impl }
376420 } else {
377 DelegationGenerics::generate_all(sig_params, GenericsPosition::Child, false)
421 DelegationGenerics::generate_all(sig_child_params, GenericsPosition::Child, trait_impl)
378422 };
379423
380424 GenericsGenerationResults {
381425 parent: GenericsGenerationResult::new(parent_generics),
382426 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 {
385429 true => hir::DelegationSelfTyPropagationKind::SelfParam,
386 false => match qself_is_infer {
430 false => match res.qself_is_infer {
387431 true => hir::DelegationSelfTyPropagationKind::SelfParam,
388432 // HirId is filled during generic args propagation.
389433 false => hir::DelegationSelfTyPropagationKind::SelfTy(HirId::INVALID),
......@@ -403,7 +447,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
403447 /// infers than generic params then we will not process all infers thus not generating
404448 /// more generic params then needed (anyway it is an error).
405449 fn create_slots_from_args(
406 &self,
450 tcx: TyCtxt<'_>,
407451 args: &AngleBracketedArgs,
408452 params: &'hir [ty::GenericParamDef],
409453 add_first_self: bool,
......@@ -444,11 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
444488 (kw::Underscore, kw::UnderscoreLifetime)
445489 };
446490
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 });
452492 }
453493
454494 slots.push(match is_infer {
......@@ -459,7 +499,42 @@ impl<'hir> LoweringContext<'_, 'hir> {
459499
460500 slots
461501 }
502}
503
504impl<'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}
462536
537impl<'hir> LoweringContext<'_, 'hir> {
463538 fn uplift_delegation_generic_params(
464539 &mut self,
465540 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
39use std::iter;
40
41use ast::visit::Visitor;
42use generics::GenericsGenerationResult;
43use hir::HirId;
44use hir::def::Res;
45use rustc_abi::ExternAbi;
46use rustc_ast as ast;
47use rustc_ast::*;
48use rustc_hir::{self as hir, FnDeclFlags};
49use rustc_middle::ty::Asyncness;
50use rustc_span::def_id::DefId;
51use rustc_span::symbol::kw;
52use rustc_span::{Ident, Span, Symbol, sym};
53
54use crate::delegation::generics::{GenericsGenerationResults, GenericsPosition};
55use crate::delegation::resolution::resolver::DelegationResolver;
56use crate::delegation::resolution::{DelegationResolution, ParamInfo};
57use crate::{
58 AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
59};
60
61mod attributes;
62mod generics;
63mod resolution;
64
65pub(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
72impl<'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
537struct SelfResolver<'a, 'b, 'hir> {
538 ctxt: &'a mut LoweringContext<'b, 'hir>,
539 path_id: NodeId,
540 self_param_id: NodeId,
541}
542
543impl 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
554impl<'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 @@
1use std::ops::ControlFlow;
2
3use ast::visit::Visitor;
4use hir::def::DefKind;
5use rustc_ast as ast;
6use rustc_ast::*;
7use rustc_data_structures::fx::FxHashSet;
8use rustc_hir as hir;
9use rustc_middle::span_bug;
10use rustc_span::def_id::{DefId, LocalDefId};
11use rustc_span::{ErrorGuaranteed, Span};
12
13use crate::delegation::generics::GenericsGenerationResults;
14use crate::delegation::resolution::resolver::DelegationResolver;
15use crate::diagnostics::{
16 CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion,
17 DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee,
18};
19
20/// Summary info about function parameters.
21#[derive(Debug, Clone, Copy, Eq, PartialEq)]
22pub(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
33pub(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
44pub(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
96impl<'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> {
567567 hir::ItemKind::Macro(ident, macro_def, macro_kinds)
568568 }
569569 ItemKind::Delegation(delegation) => {
570 let delegation_results = self.lower_delegation(delegation, id);
570 let delegation_results = self.lower_delegation(delegation);
571571 hir::ItemKind::Fn {
572572 sig: delegation_results.sig,
573573 ident: delegation_results.ident,
......@@ -1052,7 +1052,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
10521052 (*ident, generics, kind, ty.is_some())
10531053 }
10541054 AssocItemKind::Delegation(delegation) => {
1055 let delegation_results = self.lower_delegation(delegation, i.id);
1055 let delegation_results = self.lower_delegation(delegation);
10561056 let item_kind = hir::TraitItemKind::Fn(
10571057 delegation_results.sig,
10581058 hir::TraitFn::Provided(delegation_results.body_id),
......@@ -1264,7 +1264,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12641264 )
12651265 }
12661266 AssocItemKind::Delegation(delegation) => {
1267 let delegation_results = self.lower_delegation(delegation, i.id);
1267 let delegation_results = self.lower_delegation(delegation);
12681268 (
12691269 delegation.ident,
12701270 (
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs+2-2
......@@ -585,11 +585,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
585585 NllRegionVariableOrigin::FreeRegion,
586586 outlived_region,
587587 );
588 let BlameConstraint { category, from_closure, cause, .. } = blame_constraint;
588 let BlameConstraint { category, from_closure, span, .. } = blame_constraint;
589589
590590 let outlived_fr_name = self.give_region_a_name(outlived_region);
591591
592 (category, from_closure, cause.span, outlived_fr_name, path)
592 (category, from_closure, span, outlived_fr_name, path)
593593 }
594594
595595 /// 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> {
414414 };
415415
416416 // 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);
419420
420421 // FIXME these methods should have better names, and also probably not be this generic.
421422 // FIXME note that we *throw away* the error element here! We probably want to
......@@ -448,17 +449,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
448449
449450 let (blame_constraint, path) =
450451 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;
452453
453 debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
454 debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info);
454455
455456 // Check if we can use one of the "nice region errors".
456457 if let (Some(f), Some(o)) =
457458 (self.regioncx.to_error_region(fr), self.regioncx.to_error_region(outlived_fr))
458459 {
459460 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);
462462 if let Some(diag) = nice.try_report_from_nll() {
463463 self.buffer_error(diag);
464464 return;
......@@ -475,7 +475,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
475475 fr_is_local, outlived_fr_is_local, category
476476 );
477477
478 let errci = ErrorConstraintInfo { fr, outlived_fr, category, span: cause.span };
478 let errci = ErrorConstraintInfo { fr, outlived_fr, category, span };
479479
480480 let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
481481 (ConstraintCategory::SolverRegionConstraint(span), _, _) => {
compiler/rustc_borrowck/src/region_infer/mod.rs+28-21
......@@ -1346,7 +1346,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
13461346 propagated_outlives_requirements.push(ClosureOutlivesRequirement {
13471347 subject: ClosureOutlivesSubject::Region(fr_minus),
13481348 outlived_free_region: fr_plus,
1349 blame_span: blame_constraint.cause.span,
1349 blame_span: blame_constraint.span,
13501350 category: blame_constraint.category,
13511351 });
13521352 }
......@@ -1652,24 +1652,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16521652 .collect::<Vec<_>>()
16531653 );
16541654
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
16731655 // When reporting an error, there is typically a chain of constraints leading from some
16741656 // "source" region which must outlive some "target" region.
16751657 // In most cases, we prefer to "blame" the constraints closer to the target --
......@@ -1836,7 +1818,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18361818 let blame_constraint = BlameConstraint {
18371819 category: best_constraint.category,
18381820 from_closure: best_constraint.from_closure,
1839 cause: ObligationCause::new(best_constraint.span, CRATE_DEF_ID, cause_code.clone()),
1821 span: best_constraint.span,
18401822 variance_info: best_constraint.variance_info,
18411823 };
18421824 (blame_constraint, path)
......@@ -1917,6 +1899,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
19171899pub(crate) struct BlameConstraint<'tcx> {
19181900 pub category: ConstraintCategory<'tcx>,
19191901 pub from_closure: bool,
1920 pub cause: ObligationCause<'tcx>,
1902 pub span: Span,
19211903 pub variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
19221904}
1905
1906impl<'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(
620620 if cfg!(feature = "llvm_enzyme") && enable_ad && !thin {
621621 let opt_stage = llvm::OptStage::FatLTO;
622622 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 {
624626 unsafe {
625627 write::llvm_optimize(
626628 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(
566566 let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore);
567567 let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter);
568568 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());
569577 let merge_functions;
570578 let unroll_loops;
571579 let vectorize_slp;
......@@ -795,6 +803,8 @@ pub(crate) unsafe fn llvm_optimize(
795803 llvm_selfprofiler,
796804 selfprofile_before_pass_callback,
797805 selfprofile_after_pass_callback,
806 passes_after_enzyme_ptr,
807 passes_after_enzyme_len,
798808 extra_passes.as_c_char_ptr(),
799809 extra_passes.len(),
800810 llvm_plugins.as_c_char_ptr(),
compiler/rustc_codegen_llvm/src/llvm/ffi.rs+2
......@@ -2492,6 +2492,8 @@ unsafe extern "C" {
24922492 llvm_selfprofiler: *mut c_void,
24932493 begin_callback: SelfProfileBeforePassCallback,
24942494 end_callback: SelfProfileAfterPassCallback,
2495 PostEnzymePasses: *const c_char,
2496 PostEnzymePassesLen: size_t,
24952497 ExtraPasses: *const c_char,
24962498 ExtraPassesLen: size_t,
24972499 LLVMPlugins: *const c_char,
compiler/rustc_codegen_ssa/src/back/write.rs+5
......@@ -106,6 +106,7 @@ pub struct ModuleConfig {
106106 pub emit_lifetime_markers: bool,
107107 pub llvm_plugins: Vec<String>,
108108 pub autodiff: Vec<config::AutoDiff>,
109 pub autodiff_post_passes: Option<String>,
109110 pub offload: Vec<config::Offload>,
110111}
111112
......@@ -257,6 +258,10 @@ impl ModuleConfig {
257258 emit_lifetime_markers: sess.emit_lifetime_markers(),
258259 llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]),
259260 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 ),
260265 offload: if_regular!(sess.opts.unstable_opts.offload.clone(), vec![]),
261266 }
262267 }
compiler/rustc_const_eval/src/interpret/step.rs+3-2
......@@ -552,16 +552,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
552552 let old_stack = self.frame_idx();
553553 let old_loc = self.frame().loc;
554554
555 // Evaluation order consistent with assignment: destination first.
556 let dest_place = self.eval_place(destination)?;
555557 let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
556558 self.eval_callee_and_args(terminator, func, args, &destination)?;
557559
558 let destination = self.eval_place(destination)?;
559560 self.init_fn_call(
560561 callee,
561562 (fn_sig.abi(), fn_abi),
562563 &args,
563564 with_caller_location,
564 &destination,
565 &dest_place,
565566 target,
566567 if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
567568 )?;
compiler/rustc_expand/src/expand.rs+2-38
......@@ -5,7 +5,7 @@ use std::{iter, mem, slice};
55
66use rustc_ast::mut_visit::*;
77use rustc_ast::tokenstream::TokenStream;
8use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
8use rustc_ast::visit::{AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
99use rustc_ast::{
1010 self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec,
1111 DUMMY_NODE_ID, DelegationSource, DelegationSuffixes, EarlyParsedAttribute, ExprKind,
......@@ -20,7 +20,7 @@ use rustc_attr_parsing::{
2020};
2121use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
2222use rustc_data_structures::stack::ensure_sufficient_stack;
23use rustc_errors::{PResult, msg};
23use rustc_errors::PResult;
2424use rustc_feature::Features;
2525use rustc_hir::Target;
2626use rustc_hir::def::MacroKinds;
......@@ -29,7 +29,6 @@ use rustc_parse::parser::{
2929 AllowConstBlockItems, AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser,
3030 RecoverColon, RecoverComma, Recovery, token_descr,
3131};
32use rustc_session::Session;
3332use rustc_session::errors::feature_err;
3433use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
3534use rustc_span::hygiene::SyntaxContext;
......@@ -770,7 +769,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
770769 }
771770 InvocationKind::Attr { attr, pos, mut item, derives } => {
772771 if let Some(expander) = ext.as_attr() {
773 self.gate_proc_macro_input(&item);
774772 self.gate_proc_macro_attr_item(span, &item);
775773 let tokens = match &item {
776774 // FIXME: Collect tokens and use them instead of generating
......@@ -904,9 +902,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
904902 InvocationKind::Derive { path, item, is_const } => match ext {
905903 SyntaxExtensionKind::Derive(expander)
906904 | SyntaxExtensionKind::LegacyDerive(expander) => {
907 if let SyntaxExtensionKind::Derive(..) = ext {
908 self.gate_proc_macro_input(&item);
909 }
910905 // The `MetaItem` representing the trait to derive can't
911906 // have an unsafe around it (as of now).
912907 let meta = ast::MetaItem {
......@@ -1043,37 +1038,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
10431038 .emit();
10441039 }
10451040
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
10771041 fn parse_ast_fragment(
10781042 &mut self,
10791043 toks: TokenStream,
compiler/rustc_feature/src/unstable.rs+1-1
......@@ -696,7 +696,7 @@ declare_features! (
696696 (unstable, powerpc_target_feature, "1.27.0", Some(150255)),
697697 /// The prfchw target feature on x86.
698698 (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.
700700 (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
701701 /// Allows the use of raw-dylibs on ELF platforms
702702 (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;
1010use rustc_hir::def_id::{DefId, LocalDefId};
1111use rustc_hir::lang_items::LangItem;
1212use rustc_infer::infer::{self, InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
13use rustc_infer::traits::{Obligation, PredicateObligations};
13use rustc_infer::traits::Obligation;
1414use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
1515use rustc_middle::ty::print::PrintTraitRefExt as _;
1616use rustc_middle::ty::relate::solver_relating::RelateExt;
......@@ -469,37 +469,6 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
469469 }
470470}
471471
472fn 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
503472pub(crate) fn reborrow_info<'tcx>(
504473 tcx: TyCtxt<'tcx>,
505474 impl_did: LocalDefId,
......@@ -552,8 +521,12 @@ pub(crate) fn reborrow_info<'tcx>(
552521 return Ok(());
553522 }
554523
524 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
555525 // We've found some data fields. They must all be either be Copy or Reborrow.
556526 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))?;
557530 if assert_field_type_is_reborrow(
558531 tcx,
559532 &infcx,
......@@ -620,17 +593,16 @@ pub(crate) fn coerce_shared_info<'tcx>(
620593 }
621594
622595 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);
633597 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
634606 assert!(!source.has_escaping_bound_vars());
635607
636608 let data = match (source.kind(), target.kind()) {
......@@ -672,6 +644,20 @@ pub(crate) fn coerce_shared_info<'tcx>(
672644 // them below.
673645 let (a, span_a) = a_data_fields[0];
674646 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))?;
675661
676662 Some((a, b, coerce_shared_trait, span_a, span_b))
677663 } else {
......@@ -696,12 +682,19 @@ pub(crate) fn coerce_shared_info<'tcx>(
696682 //
697683 // 1 data field each; they must be the same type and Copy, or relate to one another using
698684 // 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.
699691 if source.ref_mutability() == Some(ty::Mutability::Mut)
700692 && target.ref_mutability() == Some(ty::Mutability::Not)
701693 && infcx
702 .eq_structurally_relating_aliases(
694 .relate(
703695 param_env,
704696 source.peel_refs(),
697 ty::Variance::Invariant,
705698 target.peel_refs(),
706699 source_field_span,
707700 )
......@@ -710,14 +703,16 @@ pub(crate) fn coerce_shared_info<'tcx>(
710703 // &mut T implements CoerceShared to &T, except not really.
711704 return Ok(());
712705 }
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.
713709 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)
715711 .is_err()
716712 {
717713 // The two data fields don't agree on a common type; this means
718714 // that they must be `A: CoerceShared<B>`. Register an obligation
719715 // for that.
720 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
721716 let cause = traits::ObligationCause::misc(span, impl_did);
722717 let obligation = Obligation::new(
723718 tcx,
......@@ -735,6 +730,8 @@ pub(crate) fn coerce_shared_info<'tcx>(
735730 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
736731 } else {
737732 // Types match: check that it is Copy.
733 //
734 // FIXME(reborrow): We should resolve regions here.
738735 assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, source, source_field_span)?;
739736 }
740737 }
......@@ -754,19 +751,20 @@ fn generic_lifetime_params_count(args: &[ty::GenericArg<'_>]) -> usize {
754751 args.iter().filter(|arg| arg.as_region().is_some()).count()
755752}
756753
757// FIXME(#155345): This should return `Unnormalized`
758754fn collect_struct_data_fields<'tcx>(
759755 tcx: TyCtxt<'tcx>,
760756 def: ty::AdtDef<'tcx>,
761757 args: ty::GenericArgsRef<'tcx>,
762) -> Vec<(Ty<'tcx>, Span)> {
758) -> Vec<(Unnormalized<'tcx, Ty<'tcx>>, Span)> {
763759 def.non_enum_variant()
764760 .fields
765761 .iter()
766762 .filter_map(|f| {
767763 // 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() {
770768 return None;
771769 }
772770 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(
9797 );
9898
9999 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());
101107
102108 // If the impl is in the same crate as the auto-trait, almost anything
103109 // goes.
compiler/rustc_interface/src/tests.rs+1
......@@ -788,6 +788,7 @@ fn test_unstable_options_tracking_hash() {
788788 tracked!(annotate_moves, AnnotateMoves::Enabled(Some(1234)));
789789 tracked!(assume_incomplete_release, true);
790790 tracked!(autodiff, vec![AutoDiff::Enable, AutoDiff::NoTT]);
791 tracked!(autodiff_post_passes, Some("function(mem2reg,instsimplify,simplifycfg)".to_string()));
791792 tracked!(binary_dep_depinfo, true);
792793 tracked!(box_noalias, false);
793794 tracked!(
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp+113-102
......@@ -616,6 +616,7 @@ extern "C" LLVMRustResult LLVMRustOptimize(
616616 bool DebugInfoForProfiling, void *LlvmSelfProfiler,
617617 LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
618618 LLVMRustSelfProfileAfterPassCallback AfterPassCallback,
619 const char *PostEnzymePasses, size_t PostEnzymePassesLen,
619620 const char *ExtraPasses, size_t ExtraPassesLen, const char *LLVMPlugins,
620621 size_t LLVMPluginsLen) {
621622 Module *TheModule = unwrap(ModuleRef);
......@@ -852,120 +853,130 @@ extern "C" LLVMRustResult LLVMRustOptimize(
852853 raw_string_ostream ThinLinkDataOS(ThinLTOSummaryBuffer->data);
853854 bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO ||
854855 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);
882898 }
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;
889914 }
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;
905915 }
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);
906923 }
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 }
915924
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 }
922932 }
923 }
924933
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());
938937 }
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 }
942953 }
943 }
944954
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 }
957967
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 }
964974
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 }
969980 }
970981 }
971982
compiler/rustc_middle/src/mir/syntax.rs+7-4
......@@ -306,9 +306,9 @@ pub enum StatementKind<'tcx> {
306306 /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except
307307 /// without the possibility of dropping the previous value (that must be done separately, if at
308308 /// 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,
312312 /// erase provenance from non-pointer types, and implicitly "retag" all references and boxes
313313 /// that it copies, meaning that the resulting value is not an exact duplicate for all intents
314314 /// and purposes of the original value.
......@@ -780,6 +780,9 @@ pub enum TerminatorKind<'tcx> {
780780 /// operands not aliasing the return place. It is unclear how this is justified in MIR, see
781781 /// [#71117].
782782 ///
783 /// The evaluation order is currently "first compute destination place, then `func` operand,
784 /// then the arguments in left-to-right order".
785 ///
783786 /// [#71117]: https://github.com/rust-lang/rust/issues/71117
784787 Call {
785788 /// The function that’s being called.
......@@ -1493,7 +1496,7 @@ pub enum CastKind {
14931496 /// but running a transmute between differently-sized types is UB.
14941497 Transmute,
14951498
1496 /// A `Subtype` cast is applied to any `StatementKind::Assign` where
1499 /// A `Subtype` cast is applied to any [`StatementKind::Assign`] where
14971500 /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
14981501 /// explicit during optimizations and codegen.
14991502 ///
compiler/rustc_mir_build/src/builder/block.rs+3-3
......@@ -184,7 +184,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
184184
185185 // Declare the bindings, which may create a source scope.
186186 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);
188188 let_scope_stack.push(remainder_scope);
189189
190190 let visibility_scope =
......@@ -242,7 +242,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
242242 this.block_context.push(BlockFrame::Statement { ignores_expr_result });
243243
244244 // Enter the remainder scope, i.e., the bindings' destruction scope.
245 this.push_scope((*remainder_scope, source_info));
245 this.push_scope(*remainder_scope);
246246 let_scope_stack.push(remainder_scope);
247247
248248 // Declare the bindings, which may create a source scope.
......@@ -346,7 +346,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
346346 // Finally, we pop all the let scopes before exiting out from the scope of block
347347 // itself.
348348 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();
350350 }
351351 // Restore the original source scope.
352352 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> {
726726 // This can be `None` if the expression's temporary scope was extended so that it can be
727727 // borrowed by a `const` or `static`. In that case, it's never dropped.
728728 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);
730731 }
731732
732733 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::*;
77use rustc_middle::thir::*;
88use tracing::{debug, instrument};
99
10use crate::builder::scope::{DropKind, LintLevel};
10use crate::builder::scope::LintLevel;
1111use crate::builder::{BlockAnd, BlockAndExtension, Builder};
1212
1313impl<'a, 'tcx> Builder<'a, 'tcx> {
......@@ -120,7 +120,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
120120 // `bar(&foo())` or anything within a block will keep the
121121 // regular drops just like runtime code.
122122 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);
124124 }
125125 }
126126 }
......@@ -128,7 +128,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
128128 block = this.expr_into_dest(temp_place, block, expr_id).into_block();
129129
130130 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);
132132 }
133133
134134 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};
2828use crate::builder::expr::as_place::PlaceBuilder;
2929use crate::builder::matches::buckets::PartitionedCandidates;
3030use crate::builder::matches::user_ty::ProjectedUserTypesNode;
31use crate::builder::scope::{DropKind, LintLevel};
31use crate::builder::scope::LintLevel;
3232use crate::builder::{
3333 BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode,
3434};
......@@ -791,7 +791,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
791791 if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id)
792792 && matches!(schedule_drop, ScheduleDrops::Yes)
793793 {
794 self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
794 self.schedule_drop_storage(span, region_scope, local_id);
795795 }
796796 let local_info = self.local_decls[local_id].local_info.as_mut().unwrap_crate_local();
797797 if let LocalInfo::User(BindingForm::Var(var_info)) = &mut **local_info {
......@@ -808,7 +808,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
808808 ) {
809809 let local_id = self.var_local_id(var, for_guard);
810810 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);
812812 }
813813 }
814814
compiler/rustc_mir_build/src/builder/mod.rs+2-3
......@@ -42,7 +42,7 @@ use rustc_middle::{bug, span_bug};
4242use rustc_span::{Span, Symbol};
4343
4444use crate::builder::expr::as_place::PlaceBuilder;
45use crate::builder::scope::{DropKind, LintLevel};
45use crate::builder::scope::LintLevel;
4646
4747pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
4848 tcx: TyCtxt<'tcx>,
......@@ -955,11 +955,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
955955 let place = Place::from(local);
956956
957957 // Make sure we drop (parts of) the argument even when not matched on.
958 self.schedule_drop(
958 self.schedule_drop_value(
959959 param.pat.as_ref().map_or(expr_span, |pat| pat.span),
960960 argument_scope,
961961 local,
962 DropKind::Value,
963962 );
964963
965964 let Some(ref pat) = param.pat else {
compiler/rustc_mir_build/src/builder/scope.rs+61-77
......@@ -162,7 +162,7 @@ struct DropData {
162162}
163163
164164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
165pub(crate) enum DropKind {
165enum DropKind {
166166 Value,
167167 Storage,
168168 ForLint,
......@@ -488,11 +488,11 @@ impl<'tcx> Scopes<'tcx> {
488488 }
489489 }
490490
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) {
492492 debug!("push_scope({:?})", region_scope);
493493 self.scopes.push(Scope {
494494 source_scope: vis_scope,
495 region_scope: region_scope.0,
495 region_scope,
496496 drops: vec![],
497497 moved_locals: vec![],
498498 cached_unwind_block: None,
......@@ -500,13 +500,13 @@ impl<'tcx> Scopes<'tcx> {
500500 });
501501 }
502502
503 fn pop_scope(&mut self, region_scope: (region::Scope, SourceInfo)) -> Scope {
503 fn pop_scope(&mut self, region_scope: region::Scope) {
504504 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);
507506 }
508507
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 {
510510 self.scopes
511511 .iter()
512512 .rposition(|scope| scope.region_scope == region_scope)
......@@ -681,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
681681 #[instrument(skip(self, f), level = "debug")]
682682 pub(crate) fn in_scope<F, R>(
683683 &mut self,
684 region_scope: (region::Scope, SourceInfo),
684 (region_scope, source_info): (region::Scope, SourceInfo),
685685 lint_level: LintLevel,
686686 f: F,
687687 ) -> BlockAnd<R>
......@@ -692,7 +692,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
692692 if let LintLevel::Explicit(current_hir_id) = lint_level {
693693 let parent_id =
694694 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);
696696 }
697697 self.push_scope(region_scope);
698698 let mut block;
......@@ -721,7 +721,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
721721 /// scope and call `pop_scope` afterwards. Note that these two
722722 /// calls must be paired; using `in_scope` as a convenience
723723 /// 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) {
725725 self.scopes.push_scope(region_scope, self.source_scope);
726726 }
727727
......@@ -730,13 +730,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
730730 /// This must match 1-to-1 with `push_scope`.
731731 pub(crate) fn pop_scope(
732732 &mut self,
733 region_scope: (region::Scope, SourceInfo),
733 region_scope: region::Scope,
734734 mut block: BasicBlock,
735735 ) -> BlockAnd<()> {
736736 debug!("pop_scope({:?}, {:?})", region_scope, block);
737737
738738 block = self.leave_top_scope(block);
739
740739 self.scopes.pop_scope(region_scope);
741740
742741 block.unit()
......@@ -804,7 +803,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
804803 }
805804
806805 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);
808807 let drops = if destination.is_some() {
809808 &mut self.scopes.breakable_scopes[break_index].break_drops
810809 } else {
......@@ -822,7 +821,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
822821 };
823822
824823 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..] {
826825 for drop in &scope.drops {
827826 drop_idx = drops.add_drop(*drop, drop_idx);
828827 }
......@@ -1007,9 +1006,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10071006 self.block_context.pop();
10081007
10091008 let discr = self.temp(discriminant_ty, source_info.span);
1010 let scope_index = self
1009 let stack_index = self
10111010 .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);
10131012 let scope = &mut self.scopes.const_continuable_scopes[break_index];
10141013 self.cfg.push_assign(block, source_info, discr, rvalue);
10151014 let drop_and_continue_block = self.cfg.start_new_block();
......@@ -1022,7 +1021,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10221021
10231022 let drops = &mut scope.const_continue_drops;
10241023
1025 let drop_idx = self.scopes.scopes[scope_index + 1..]
1024 let drop_idx = self.scopes.scopes[stack_index + 1..]
10261025 .iter()
10271026 .flat_map(|scope| &scope.drops)
10281027 .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx));
......@@ -1032,10 +1031,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10321031 self.cfg.terminate(imaginary_target, source_info, TerminatorKind::UnwindResume);
10331032
10341033 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);
10361035 let mut drops = DropTree::new();
10371036
1038 let drop_idx = self.scopes.scopes[scope_index + 1..]
1037 let drop_idx = self.scopes.scopes[stack_index + 1..]
10391038 .iter()
10401039 .flat_map(|scope| &scope.drops)
10411040 .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx));
......@@ -1066,14 +1065,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10661065 .unwrap_or_else(|| span_bug!(source_info.span, "no if-then scope found"));
10671066
10681067 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);
10701069
10711070 // Upgrade `if_then_scope` to `&mut`.
10721071 let if_then_scope = self.scopes.if_then_scope.as_mut().expect("upgrading & to &mut");
10731072
10741073 let mut drop_idx = ROOT_NODE;
10751074 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..] {
10771076 for drop in &scope.drops {
10781077 drop_idx = drops.add_drop(*drop, drop_idx);
10791078 }
......@@ -1390,47 +1389,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13901389 // Scheduling drops
13911390 // ================
13921391
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
14031392 /// Indicates that `place` should be dropped on exit from `region_scope`.
14041393 ///
14051394 /// When called with `DropKind::Storage`, `place` shouldn't be the return
14061395 /// place, or a function parameter.
1407 pub(crate) fn schedule_drop(
1396 fn schedule_drop(
14081397 &mut self,
14091398 span: Span,
14101399 region_scope: region::Scope,
14111400 local: Local,
14121401 drop_kind: DropKind,
14131402 ) {
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
14341403 // When building drops, we try to cache chains of drops to reduce the
14351404 // number of `DropTree::add_drop` calls. This, however, means that
14361405 // whenever we add a drop into a scope which already had some entries
......@@ -1477,7 +1446,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14771446 // path, we only need to invalidate the cache for drops that happen on
14781447 // the unwind or coroutine drop paths. This means that for
14791448 // 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 };
14811453 for scope in self.scopes.scopes.iter_mut().rev() {
14821454 if invalidate_caches {
14831455 scope.invalidate_cache();
......@@ -1501,6 +1473,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15011473 span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
15021474 }
15031475
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
15041509 /// Schedule emission of a backwards incompatible drop lint hint.
15051510 /// Applicable only to temporary values for now.
15061511 #[instrument(level = "debug", skip(self))]
......@@ -1512,28 +1517,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15121517 ) {
15131518 // Note that we are *not* gating BIDs here on whether they have significant destructor.
15141519 // 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);
15371521 }
15381522
15391523 /// Indicates that the "local operand" stored in `local` is
......@@ -1611,7 +1595,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16111595 /// It is possible to unwind to some ancestor scope if some drop panics as
16121596 /// the program breaks out of a if-then scope.
16131597 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);
16151599 let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target]
16161600 .iter()
16171601 .enumerate()
......@@ -1674,7 +1658,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16741658 self.coroutine.is_some(),
16751659 "diverge_dropline_target is valid only for coroutine"
16761660 );
1677 let target = self.scopes.scope_index(target_scope, span);
1661 let target = self.scopes.stack_index(target_scope, span);
16781662 let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target]
16791663 .iter()
16801664 .enumerate()
compiler/rustc_resolve/src/build_reduced_graph.rs+1-1
......@@ -475,7 +475,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
475475 }
476476
477477 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) {
479479 Ok(vis) => vis,
480480 Err(error) => {
481481 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> {
11551155 resolution.as_ref().and_then(|r| r.non_glob_decl).filter(|b| Some(*b) != ignore_decl);
11561156
11571157 if let Some(finalize) = finalize {
1158 // finalize implies that the module is fully expanded
1159 assert!(!module.has_unexpanded_invocations());
11581160 return self.get_mut().finalize_module_binding(
11591161 ident,
11601162 orig_ident_span,
......@@ -1219,6 +1221,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
12191221 resolution.as_ref().and_then(|r| r.glob_decl).filter(|b| Some(*b) != ignore_decl);
12201222
12211223 if let Some(finalize) = finalize {
1224 // finalize implies that the module is fully expanded
1225 assert!(!module.has_unexpanded_invocations());
12221226 return self.get_mut().finalize_module_binding(
12231227 ident,
12241228 orig_ident_span,
compiler/rustc_session/src/options.rs+2
......@@ -2298,6 +2298,8 @@ options! {
22982298 `=LooseTypes`
22992299 `=Inline`
23002300 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)"),
23012303 #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
23022304 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
23032305 "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! {
991991 /// On PowerPC only: build for SPE.
992992 PowerPcSpe = "powerpc-spe",
993993 /// 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",
995995 }
996996
997997 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
167167 }
168168}
169169
170impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &T {
170impl<I: Interner, T: TypeVisitable<I> + ?Sized> TypeVisitable<I> for &T {
171171 fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
172172 (**self).visit_with(visitor)
173173 }
......@@ -179,7 +179,7 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> {
179179 }
180180}
181181
182impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> {
182impl<I: Interner, T: TypeVisitable<I> + ?Sized> TypeVisitable<I> for Box<T> {
183183 fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
184184 (**self).visit_with(visitor)
185185 }
......@@ -209,14 +209,14 @@ impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for Smal
209209// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
210210// case, because we can't return a new slice. But note that there are a couple
211211// of trivial impls of `TypeFoldable` for specific slice types elsewhere.
212impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
212impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for [T] {
213213 fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
214214 walk_visitable_list!(visitor, self.iter());
215215 V::Result::output()
216216 }
217217}
218218
219impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
219impl<const N: usize, I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for [T; N] {
220220 fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
221221 walk_visitable_list!(visitor, self.iter());
222222 V::Result::output()
library/alloc/src/boxed.rs+2
......@@ -218,6 +218,8 @@ mod iter;
218218/// [`ThinBox`] implementation.
219219mod thin;
220220
221#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
222pub use iter::BoxedArrayIntoIter;
221223#[unstable(feature = "thin_box", issue = "92791")]
222224pub use thin::ThinBox;
223225
library/alloc/src/boxed/iter.rs+155-3
......@@ -1,18 +1,19 @@
11use core::async_iter::AsyncIterator;
2use core::iter::FusedIterator;
2use core::iter::{FusedIterator, TrustedLen};
3use core::num::NonZero;
34use core::pin::Pin;
45use core::slice;
56use core::task::{Context, Poll};
67
7use crate::alloc::Allocator;
8use crate::alloc::{Allocator, Global};
89#[cfg(not(no_global_oom_handling))]
910use crate::borrow::Cow;
1011use crate::boxed::Box;
1112#[cfg(not(no_global_oom_handling))]
1213use crate::string::String;
13use crate::vec;
1414#[cfg(not(no_global_oom_handling))]
1515use crate::vec::Vec;
16use crate::{fmt, vec};
1617
1718#[stable(feature = "rust1", since = "1.0.0")]
1819impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
......@@ -192,3 +193,154 @@ impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
192193 String::from_iter(iter).into_boxed_str()
193194 }
194195}
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")]
200impl<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")]
205impl<'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")]
210impl<'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")]
213impl<'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")]
222impl<'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]
233pub 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
238impl<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")]
254impl<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")]
287impl<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")]
306impl<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")]
317impl<T, const N: usize, A: Allocator> FusedIterator for BoxedArrayIntoIter<T, N, A> {}
318
319#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
320unsafe 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")]
324impl<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")]
331impl<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")]
340impl<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 @@
1use crate::boxed::Box;
2use 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")]
9impl<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 @@
11//! Traits, helpers, and type definitions for core I/O functionality.
22
33mod error;
4mod impls;
45
56#[unstable(feature = "raw_os_error_ty", issue = "107792")]
67pub use core::io::RawOsError;
......@@ -17,4 +18,4 @@ pub use core::io::{
1718};
1819#[doc(hidden)]
1920#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
20pub use core::io::{OsFunctions, chain, take};
21pub use core::io::{IoHandle, OsFunctions, SizeHint, chain, take};
library/alloc/src/vec/into_iter.rs+1-1
......@@ -552,7 +552,7 @@ where
552552#[doc(hidden)]
553553#[unstable(issue = "none", feature = "std_internals")]
554554#[rustc_unsafe_specialization_marker]
555pub trait NonDrop {}
555trait NonDrop {}
556556
557557// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
558558// 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> {
3434 }
3535}
3636
37#[stable(feature = "boxed_array_value_iter", since = "CURRENT_RUSTC_VERSION")]
38impl<T, const N: usize> !Iterator for [T; N] {}
39
3740// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator`
3841// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
3942// 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> {}
365368#[doc(hidden)]
366369#[unstable(issue = "none", feature = "std_internals")]
367370#[rustc_unsafe_specialization_marker]
368pub trait NonDrop {}
371trait NonDrop {}
369372
370373// T: Copy as approximation for !Drop since get_unchecked does not advance self.alive
371374// and thus we can't implement drop-handling
library/core/src/io/impls.rs created+35
......@@ -0,0 +1,35 @@
1use 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")]
8impl<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")]
25impl 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 @@
33mod borrowed_buf;
44mod cursor;
55mod error;
6mod impls;
67mod io_slice;
8mod size_hint;
79mod util;
810
911#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
......@@ -25,5 +27,26 @@ pub use self::{
2527#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
2628pub use self::{
2729 error::{Custom, CustomOwner, OsFunctions},
30 size_hint::SizeHint,
2831 util::{chain, take},
2932};
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")]
52pub 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")]
13pub 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")]
50impl<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 @@
1use crate::fmt;
1use crate::io::SizeHint;
2use crate::{cmp, fmt};
23
34/// `Empty` ignores any data written via [`Write`], and will always be empty
45/// (returning zero bytes) when read via [`Read`].
......@@ -13,6 +14,15 @@ use crate::fmt;
1314#[derive(Copy, Clone, Debug, Default)]
1415pub struct Empty;
1516
17#[doc(hidden)]
18#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
19impl SizeHint for Empty {
20 #[inline]
21 fn upper_bound(&self) -> Option<usize> {
22 Some(0)
23 }
24}
25
1626/// Creates a value that is always at EOF for reads, and ignores all data written.
1727///
1828/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
......@@ -63,6 +73,20 @@ pub struct Repeat {
6373 pub byte: u8,
6474}
6575
76#[doc(hidden)]
77#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
78impl 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
6690/// Creates an instance of a reader that infinitely repeats one byte.
6791///
6892/// All reads from this reader will succeed by filling the specified buffer with
......@@ -145,6 +169,23 @@ pub struct Chain<T, U> {
145169 pub done_first: bool,
146170}
147171
172#[doc(hidden)]
173#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
174impl<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
148189impl<T, U> Chain<T, U> {
149190 /// Consumes the `Chain`, returning the wrapped readers.
150191 ///
......@@ -253,6 +294,23 @@ pub struct Take<T> {
253294 pub limit: u64,
254295}
255296
297#[doc(hidden)]
298#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
299impl<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
256314impl<T> Take<T> {
257315 /// Returns the number of bytes that can be read before this instance will
258316 /// return EOF.
library/core/src/iter/adapters/array_chunks.rs+3-9
......@@ -1,8 +1,6 @@
11use crate::array;
22use crate::iter::adapters::SourceIter;
3use crate::iter::{
4 ByRefSized, FusedIterator, InPlaceIterable, TrustedFused, TrustedRandomAccessNoCoerce,
5};
3use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedRandomAccessNoCoerce};
64use crate::num::NonZero;
75use crate::ops::{ControlFlow, NeverShortCircuit, Try};
86
......@@ -128,15 +126,11 @@ where
128126 self.next_back_remainder();
129127
130128 let mut acc = init;
131 let mut iter = ByRefSized(&mut self.iter).rev();
132129
133130 // 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
135132 // (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() {
140134 acc = f(acc, chunk)?
141135 }
142136
library/core/src/mem/mod.rs+39-5
......@@ -35,6 +35,7 @@ use crate::clone::TrivialClone;
3535use crate::cmp::Ordering;
3636use crate::marker::{Destruct, DiscriminantKind};
3737use crate::panic::const_assert;
38use crate::ub_checks::assert_unsafe_precondition;
3839use crate::{clone, cmp, fmt, hash, intrinsics, ptr};
3940
4041mod alignment;
......@@ -1077,6 +1078,27 @@ pub const fn copy<T: Copy>(x: &T) -> T {
10771078///
10781079/// [ub]: ../../reference/behavior-considered-undefined.html
10791080///
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///
10801102/// # Examples
10811103///
10821104/// ```
......@@ -1101,20 +1123,32 @@ pub const fn copy<T: Copy>(x: &T) -> T {
11011123///
11021124/// // The contents of 'foo_array' should not have changed
11031125/// 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/// );
11041132/// ```
11051133#[inline]
11061134#[must_use]
11071135#[track_caller]
11081136#[stable(feature = "rust1", since = "1.0.0")]
11091137#[rustc_const_stable(feature = "const_transmute_copy", since = "1.74.0")]
1110pub 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"
1138pub 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
11141148 );
11151149
11161150 // 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) {
11181152 // SAFETY: `src` is a reference which is guaranteed to be valid for reads.
11191153 // The caller must guarantee that the actual transmutation is safe.
11201154 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() {
138138 assert_eq!(0_u64, unsafe { transmute_copy(&u.b) });
139139}
140140
141#[test]
142#[cfg(panic = "unwind")]
143fn 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
167141#[test]
168142#[allow(dead_code)]
169143fn test_discriminant_send_sync() {
library/std/src/fs.rs+2
......@@ -1540,6 +1540,8 @@ impl Seek for File {
15401540 (&*self).stream_position()
15411541 }
15421542}
1543#[doc(hidden)]
1544#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
15431545impl crate::io::IoHandle for File {}
15441546
15451547impl Dir {
library/std/src/io/buffered/bufreader.rs+2
......@@ -580,6 +580,8 @@ impl<R: ?Sized + Seek> Seek for BufReader<R> {
580580 }
581581}
582582
583#[doc(hidden)]
584#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
583585impl<T: ?Sized> SizeHint for BufReader<T> {
584586 #[inline]
585587 fn lower_bound(&self) -> usize {
library/std/src/io/mod.rs+2-104
......@@ -299,7 +299,7 @@ mod tests;
299299
300300use core::slice::memchr;
301301
302use alloc_crate::io::OsFunctions;
302pub(crate) use alloc_crate::io::IoHandle;
303303#[unstable(feature = "raw_os_error_ty", issue = "107792")]
304304pub use alloc_crate::io::RawOsError;
305305#[doc(hidden)]
......@@ -315,6 +315,7 @@ pub use alloc_crate::io::{
315315};
316316#[stable(feature = "iovec", since = "1.36.0")]
317317pub use alloc_crate::io::{IoSlice, IoSliceMut};
318use alloc_crate::io::{OsFunctions, SizeHint};
318319
319320#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
320321pub use self::buffered::WriterPanicked;
......@@ -1980,21 +1981,6 @@ pub enum SeekFrom {
19801981 Current(#[stable(feature = "rust1", since = "1.0.0")] i64),
19811982}
19821983
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
1996pub(crate) trait IoHandle {}
1997
19981984fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> Result<usize> {
19991985 let mut read = 0;
20001986 loop {
......@@ -2552,21 +2538,6 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
25522538 // split between the two parts of the chain
25532539}
25542540
2555impl<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
25702541#[stable(feature = "rust1", since = "1.0.0")]
25712542impl<T: Read> Read for Take<T> {
25722543 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
......@@ -2661,21 +2632,6 @@ impl<T: BufRead> BufRead for Take<T> {
26612632 }
26622633}
26632634
2664impl<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
26792635#[stable(feature = "seek_io_take", since = "1.89.0")]
26802636impl<T: Seek> Seek for Take<T> {
26812637 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>> {
27842740 inlined_slow_read_byte(reader)
27852741}
27862742
2787trait 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
2797impl<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
2809impl<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
2821impl<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
2833impl 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
28452743/// An iterator over the contents of an instance of `BufRead` split on a
28462744/// particular byte.
28472745///
library/std/src/io/util.rs+1-20
......@@ -6,7 +6,7 @@ mod tests;
66use crate::fmt;
77use crate::io::{
88 self, BorrowedCursor, BufRead, Empty, IoSlice, IoSliceMut, Read, Repeat, Seek, SeekFrom, Sink,
9 SizeHint, Write,
9 Write,
1010};
1111
1212#[stable(feature = "rust1", since = "1.0.0")]
......@@ -102,13 +102,6 @@ impl Seek for Empty {
102102 }
103103}
104104
105impl SizeHint for Empty {
106 #[inline]
107 fn upper_bound(&self) -> Option<usize> {
108 Some(0)
109 }
110}
111
112105#[stable(feature = "empty_write", since = "1.73.0")]
113106impl Write for Empty {
114107 #[inline]
......@@ -240,18 +233,6 @@ impl Read for Repeat {
240233 }
241234}
242235
243impl 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
255236#[stable(feature = "rust1", since = "1.0.0")]
256237impl Write for Sink {
257238 #[inline]
library/test/src/lib.rs+9
......@@ -207,6 +207,14 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
207207 // If we're being run in SpawnedSecondary mode, run the test here. run_test
208208 // will then exit the process.
209209 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".
210218 unsafe {
211219 env::remove_var(SECONDARY_TEST_INVOKER_VAR);
212220 }
......@@ -214,6 +222,7 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
214222 // Convert benchmarks to tests if we're not benchmarking.
215223 let mut tests = tests.iter().map(make_owned_test).collect::<Vec<_>>();
216224 if env::var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR).is_ok() {
225 // SAFETY: Same as for SECONDARY_TEST_INVOKER_VAR
217226 unsafe {
218227 env::remove_var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR);
219228 }
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/
4141
4242# NOTE: intentionally uses python2 for x.py so we can test it still works.
4343# validate-toolstate only runs in our CI, so it's ok for it to only support python3.
44ENV SCRIPT="TIDY_PRINT_DIFF=1 python2.7 ../x.py test \
45 src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck"
44ENV 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 @@
22
33set -euo pipefail
44
5LINUX_VERSION=v7.1-rc1
5# https://github.com/rust-lang/rust/pull/157151
6LINUX_VERSION=40bc55834bc15896f4438b0936c679ef32e20df1
67
78# Build rustc, rustdoc, cargo, clippy-driver and rustfmt
89../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)"
3333echo "Running pre-push script $ROOT_DIR/x test tidy"
3434
3535cd "$ROOT_DIR"
36# The env var is necessary for printing diffs in py (fmt/lint) and cpp.
37TIDY_PRINT_DIFF=1 ./x test tidy \
36./x test tidy \
3837 --set build.locked-deps=true \
3938 --extra-checks auto:py,auto:cpp,auto:js
4039if [ $? -ne 0 ]; then
src/librustdoc/clean/inline.rs+22-15
......@@ -681,21 +681,26 @@ fn build_module(
681681// We are only interested into `Res::Def`. And in there, we only want "items" which get their own
682682// rustdoc page. So not `DefKind::Ctor` for example (which is returned by `tcx.module_children()`).
683683fn should_ignore_res(res: Res) -> bool {
684 !matches!(res, Res::Def(def_kind, _) if !should_ignore_def_kind(def_kind))
685}
686
687fn should_ignore_def_kind(kind: DefKind) -> bool {
684688 !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
699704 )
700705}
701706
......@@ -770,13 +775,15 @@ fn build_module_items(
770775 } else if let Some(def_id) = res.opt_def_id()
771776 && let Some(reexport) = item.reexport_chain.first()
772777 && let Some(reexport_def_id) = reexport.id()
778 && !should_ignore_def_kind(cx.tcx.def_kind(reexport_def_id))
773779 && find_attr!(
774780 load_attrs(cx.tcx, reexport_def_id),
775781 Doc(d)
776782 if d.inline.first().is_some_and(|(inline, _)| *inline == hir::attrs::DocInline::NoInline)
777783 )
778784 {
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, _)) {
780787 continue;
781788 }
782789 // 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 @@
1010 "vendor": "unknown",
1111 "linker": "rust-lld",
1212 "linker-flavor": "gnu-lld",
13 "rustc-abi": "x86-softfloat",
13 "rustc-abi": "softfloat",
1414 "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
1515 "dynamic-linking": false,
1616 "executables": true,
src/tools/tidy/src/deps.rs+3
......@@ -692,6 +692,9 @@ pub fn check(root: &Path, cargo: &Path, tidy_ctx: TidyCtx) {
692692
693693/// Ensure the list of proc-macro crate transitive dependencies is up to date
694694fn 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 }
695698 let mut cmd = cargo_metadata::MetadataCommand::new();
696699 cmd.cargo_path(cargo)
697700 .manifest_path(root.join("Cargo.toml"))
src/tools/tidy/src/extra_checks/mod.rs+17-22
......@@ -10,12 +10,11 @@
1010//! configuration after a double dash (`--extra-checks=py -- foo.py`)
1111//! 2. Build configuration based on args/environment:
1212//! - Formatters by default are in check only mode
13//! - If in CI (TIDY_PRINT_DIFF=1 is set), check and print the diff
1413//! - If `--bless` is provided, formatters may run
1514//! - Pass any additional config after the `--`. If no files are specified,
1615//! 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.
1918
2019use std::ffi::{OsStr, OsString};
2120use std::path::{Path, PathBuf};
......@@ -200,14 +199,12 @@ fn js_prepare(root_path: &Path, outdir: &Path, npm: &Path, tidy_ctx: &TidyCtx) -
200199
201200fn show_bless_help(mode: &str, action: &str, bless: bool) {
202201 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 );
204205 }
205206}
206207
207fn show_diff() -> bool {
208 std::env::var("TIDY_PRINT_DIFF").is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1")
209}
210
211208fn check_spellcheck(root_path: &Path, outdir: &Path, cargo: &Path, tidy_ctx: &TidyCtx) {
212209 let mut check = tidy_ctx.start_check("extra_checks:spellcheck");
213210
......@@ -314,7 +311,7 @@ fn check_python_lint(
314311
315312 let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, args);
316313
317 if res.is_err() && !bless && show_diff() {
314 if res.is_err() && !bless {
318315 eprintln!("\npython linting failed! Printing diff suggestions:");
319316
320317 let diff_res = run_ruff(
......@@ -358,18 +355,16 @@ fn check_python_fmt(
358355 let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &args);
359356
360357 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 );
373368 show_bless_help("py:fmt", "reformat Python code", bless);
374369 }
375370
......@@ -421,7 +416,7 @@ fn check_cpp_fmt(
421416 let args = merge_args(&cfg_args_clang_format, &file_args_clang_format);
422417 let res = py_runner(py_path, false, None, "clang-format", &args);
423418
424 if res.is_err() && !bless && show_diff() {
419 if res.is_err() && !bless {
425420 eprintln!("\nclang-format linting failed! Printing diff suggestions:");
426421
427422 let mut cfg_args_diff = cfg_args.clone();
tests/codegen-llvm/autodiff/abi_handling.rs+18-18
......@@ -1,7 +1,7 @@
11//@ revisions: debug release
22
33//@[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
55//@ no-prefer-dynamic
66//@ needs-enzyme
77
......@@ -39,15 +39,15 @@ fn square(x: f32) -> f32 {
3939// CHECK-NEXT: Function Attrs
4040// debug-NEXT: define internal { float, float }
4141// 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)
4444
4545// CHECK-LABEL: ; abi_handling::f1
4646// CHECK-NEXT: Function Attrs
4747// debug-NEXT: define internal float
4848// 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)
5151#[autodiff_forward(df1, Dual, Dual)]
5252#[inline(never)]
5353fn f1(x: &[f32; 2]) -> f32 {
......@@ -58,15 +58,15 @@ fn f1(x: &[f32; 2]) -> f32 {
5858// CHECK-NEXT: Function Attrs
5959// debug-NEXT: define internal { float, float }
6060// debug-SAME: (ptr %f, float %x, float %dret)
61// release-NEXT: define internal fastcc noundef float
61// release-NEXT: define internal fastcc { float, float }
6262// release-SAME: (float noundef %x)
6363
6464// CHECK-LABEL: ; abi_handling::f2
6565// CHECK-NEXT: Function Attrs
6666// debug-NEXT: define internal float
6767// 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)
7070#[autodiff_reverse(df2, Const, Active, Active)]
7171#[inline(never)]
7272fn f2(f: fn(f32) -> f32, x: f32) -> f32 {
......@@ -77,15 +77,15 @@ fn f2(f: fn(f32) -> f32, x: f32) -> f32 {
7777// CHECK-NEXT: Function Attrs
7878// debug-NEXT: define internal { float, float }
7979// 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)
8282
8383// CHECK-LABEL: ; abi_handling::f3
8484// CHECK-NEXT: Function Attrs
8585// debug-NEXT: define internal float
8686// 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)
8989#[autodiff_forward(df3, Dual, Dual, Dual)]
9090#[inline(never)]
9191fn f3<'a>(x: &'a f32, y: &'a f32) -> f32 {
......@@ -103,7 +103,7 @@ fn f3<'a>(x: &'a f32, y: &'a f32) -> f32 {
103103// CHECK-NEXT: Function Attrs
104104// debug-NEXT: define internal float
105105// debug-SAME: (float %x.0, float %x.1)
106// release-NEXT: define internal fastcc noundef float
106// release-NEXT: define internal noundef float
107107// release-SAME: (float noundef %x.0, float noundef %x.1)
108108#[autodiff_forward(df4, Dual, Dual)]
109109#[inline(never)]
......@@ -122,7 +122,7 @@ fn f4(x: (f32, f32)) -> f32 {
122122// CHECK-NEXT: Function Attrs
123123// debug-NEXT: define internal float
124124// debug-SAME: (float %i.0, float %i.1)
125// release-NEXT: define internal fastcc noundef float
125// release-NEXT: define internal noundef float
126126// release-SAME: (float noundef %i.0, float noundef %i.1)
127127#[autodiff_forward(df5, Dual, Dual)]
128128#[inline(never)]
......@@ -142,7 +142,7 @@ fn f5(i: Input) -> f32 {
142142// CHECK-NEXT: Function Attrs
143143// debug-NEXT: define internal float
144144// debug-SAME: (float %i.0, float %i.1)
145// release-NEXT: define internal fastcc noundef float
145// release-NEXT: define internal noundef float
146146// release-SAME: (float noundef %i.0, float noundef %i.1)
147147#[autodiff_forward(df6, Dual, Dual)]
148148#[inline(never)]
......@@ -155,14 +155,14 @@ fn f6(i: NestedInput) -> f32 {
155155// debug-NEXT: define internal { float, float }
156156// debug-SAME: (ptr align 4 %x.0, ptr align 4 %x.1, ptr align 4 %bx_0.0, ptr align 4 %bx_0.1)
157157// 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)
159159
160160// CHECK-LABEL: ; abi_handling::f7
161161// CHECK-NEXT: Function Attrs
162162// debug-NEXT: define internal float
163163// 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)
166166#[autodiff_forward(df7, Dual, Dual)]
167167#[inline(never)]
168168fn 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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44//
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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44
......@@ -20,22 +20,28 @@ fn square(x: &f32) -> f32 {
2020 x * x
2121}
2222
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
3327// CHECK-NEXT: }
3428
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
3733// CHECK-NEXT: }
3834
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
3945fn main() {
4046 let x = std::hint::black_box(3.0);
4147 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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44//@ revisions: F32 F64 Main
......@@ -34,7 +34,7 @@ fn square<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T {
3434// F64-NEXT: ; Function Attrs: {{.*}}
3535// F64-NEXT: define internal {{.*}} void
3636// F64-NEXT: start:
37// F64-NEXT: {{(tail )?}}call {{(fastcc )?}}void @diffe_{{.*}}(double {{.*}}, ptr {{.*}})
37// F64-NEXT: {{(tail )?}}call fast { double } @diffe_{{.*}}(ptr {{.*}}, ptr {{.*}}, double {{.*}})
3838// F64-NEXT: ret void
3939
4040// 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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44//
......@@ -32,9 +32,9 @@ fn square2(x: &f64) -> f64 {
3232// CHECK-NOT:br
3333// CHECK-NOT:ret
3434// 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 {{.*}})
3636// 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 {{.*}})
3838
3939fn main() {
4040 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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44
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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44#![feature(autodiff)]
......@@ -12,14 +12,18 @@ fn square(x: &f64) -> f64 {
1212 x * x
1313}
1414
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]]
2327// CHECK-NEXT:}
2428
2529fn 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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44
......@@ -18,17 +18,21 @@ fn primal(x: f32, y: f32) -> f64 {
1818 (x * x * y) as f64
1919}
2020
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:
2323// CHECK-NEXT: %_4 = fmul float %x, %x
2424// CHECK-NEXT: %_3 = fmul float %_4, %y
2525// 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
3236// CHECK-NEXT: }
3337
3438fn 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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44
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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44
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
22//@ no-prefer-dynamic
33//@ needs-enzyme
44
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
9use 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]
16pub 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]
31pub 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]
45pub 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]
57pub 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 @@
1pub 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
10extern 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
17pub use glob_import::*;
tests/ui/iterators/into-iter-on-arrays-2018.rs+2-3
......@@ -5,6 +5,7 @@ use std::array::IntoIter;
55use std::ops::Deref;
66use std::rc::Rc;
77use std::slice::Iter;
8use std::boxed::BoxedArrayIntoIter;
89
910fn main() {
1011 let array = [0; 10];
......@@ -15,9 +16,7 @@ fn main() {
1516 //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
1617 //~| WARNING this changes meaning
1718
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();
2120
2221 let _: Iter<'_, i32> = Rc::new(array).into_iter();
2322 //~^ 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 @@
11warning: 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
33 |
44LL | let _: Iter<'_, i32> = array.into_iter();
55 | ^^^^^^^^^
......@@ -19,16 +19,7 @@ LL + let _: Iter<'_, i32> = IntoIterator::into_iter(array);
1919 |
2020
2121warning: 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 |
24LL | 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
30warning: 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
3223 |
3324LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
3425 | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
......@@ -37,7 +28,7 @@ LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
3728 = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
3829
3930warning: 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
4132 |
4233LL | let _: Iter<'_, i32> = Array(array).into_iter();
4334 | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
......@@ -46,7 +37,7 @@ LL | let _: Iter<'_, i32> = Array(array).into_iter();
4637 = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
4738
4839warning: 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
5041 |
5142LL | for _ in [1, 2, 3].into_iter() {}
5243 | ^^^^^^^^^
......@@ -64,5 +55,5 @@ LL - for _ in [1, 2, 3].into_iter() {}
6455LL + for _ in [1, 2, 3] {}
6556 |
6657
67warning: 5 warnings emitted
58warning: 4 warnings emitted
6859
tests/ui/iterators/into-iter-on-arrays-2021.rs+2-1
......@@ -4,13 +4,14 @@
44use std::array::IntoIter;
55use std::ops::Deref;
66use std::rc::Rc;
7use std::boxed::BoxedArrayIntoIter;
78
89fn main() {
910 let array = [0; 10];
1011
1112 // In 2021, the method dispatches to `IntoIterator for [T; N]`.
1213 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();
1415
1516 // The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
1617 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() {
2222 //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
2323 //~| WARNING this changes meaning
2424
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();
3729
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();
5034
5135 // Expressions that should not
5236 (&[1, 2]).into_iter();
tests/ui/iterators/into-iter-on-arrays-lint.rs-16
......@@ -23,30 +23,14 @@ fn main() {
2323 //~| WARNING this changes meaning
2424
2525 Box::new(small).into_iter();
26 //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
27 //~| WARNING this changes meaning
2826 Box::new([1, 2]).into_iter();
29 //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
30 //~| WARNING this changes meaning
3127 Box::new(big).into_iter();
32 //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
33 //~| WARNING this changes meaning
3428 Box::new([0u8; 33]).into_iter();
35 //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
36 //~| WARNING this changes meaning
3729
3830 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
4131 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
4432 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
4733 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
5034
5135 // Expressions that should not
5236 (&[1, 2]).into_iter();
tests/ui/iterators/into-iter-on-arrays-lint.stderr+1-73
......@@ -75,77 +75,5 @@ LL - [0u8; 33].into_iter();
7575LL + IntoIterator::into_iter([0u8; 33]);
7676 |
7777
78warning: 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 |
81LL | 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
87warning: 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 |
90LL | 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
96warning: 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 |
99LL | 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
105warning: 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 |
108LL | 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
114warning: 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 |
117LL | 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
123warning: 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 |
126LL | 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
132warning: 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 |
135LL | 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
141warning: 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 |
144LL | 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
150warning: 12 warnings emitted
78warning: 4 warnings emitted
15179
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
11struct Local;
12
13auto 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.
17type ToLocal = Local;
18unsafe impl Sync for ToLocal {}
19impl 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.
23struct Inner;
24type Mid = Inner;
25type Nested = Mid;
26impl Marker for Nested {}
27
28// A generic alias instantiated with a local nominal type is accepted.
29struct Generic;
30type Id<T> = T;
31impl 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.
35struct Negated;
36type ToNeg = Negated;
37impl !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.
42struct NotSync;
43impl !Sync for NotSync {}
44type ToRef = &'static NotSync;
45unsafe 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.
49type ToDyn = dyn Send;
50impl Marker for ToDyn {}
51//~^ ERROR traits with a default impl, like `Marker`, cannot be implemented for trait object `(dyn Send + 'static)`
52
53fn main() {}
tests/ui/lazy-type-alias/auto-trait-impls.stderr created+17
......@@ -0,0 +1,17 @@
1error[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 |
4LL | 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
9error[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 |
12LL | unsafe impl Send for ToRef {}
13 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
14
15error: aborting due to 2 previous errors
16
17For 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
5fn 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
1717#[derive(Copy)] //~ ERROR `derive` may only be applied to `struct`s, `enum`s and `union`s
1818mod n {}
1919
20#[empty_attr]
21mod module; //~ ERROR file modules in proc macro input are unstable
22
23#[empty_attr]
24mod outer {
25 mod inner; //~ ERROR file modules in proc macro input are unstable
26
27 mod inner_inline {} // OK
28}
29
30#[derive(Empty)]
31struct 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]
41fn 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
4720fn main() {}
tests/ui/proc-macro/attributes-on-modules-fail.stderr+2-42
......@@ -6,46 +6,6 @@ LL | #[derive(Copy)]
66LL | mod n {}
77 | -------- not a `struct`, `enum` or `union`
88
9error[E0658]: file modules in proc macro input are unstable
10 --> $DIR/attributes-on-modules-fail.rs:21:1
11 |
12LL | 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
19error[E0658]: file modules in proc macro input are unstable
20 --> $DIR/attributes-on-modules-fail.rs:25:5
21 |
22LL | 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
29error[E0658]: file modules in proc macro input are unstable
30 --> $DIR/attributes-on-modules-fail.rs:34:9
31 |
32LL | 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
39error[E0658]: file modules in proc macro input are unstable
40 --> $DIR/attributes-on-modules-fail.rs:43:5
41 |
42LL | 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
499error[E0425]: cannot find type `Y` in this scope
5010 --> $DIR/attributes-on-modules-fail.rs:11:14
5111 |
......@@ -68,7 +28,7 @@ help: consider importing this struct
6828LL + use m::X;
6929 |
7030
71error: aborting due to 7 previous errors
31error: aborting due to 3 previous errors
7232
73Some errors have detailed explanations: E0425, E0658, E0774.
33Some errors have detailed explanations: E0425, E0774.
7434For 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
3extern crate proc_macro;
4
5use proc_macro::TokenStream;
6
7#[proc_macro_attribute]
8pub 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]
17pub 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)]
27pub 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]
37fn 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;
99
1010#[deny(unused_attributes)]
1111mod 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
1413
1514fn main() {}
1615
tests/ui/proc-macro/inner-attr-file-mod.stderr+1-11
......@@ -18,16 +18,6 @@ LL | #![print_attr]
1818 = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
1919 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2020
21error[E0658]: file modules in proc macro input are unstable
22 --> $DIR/inner-attr-file-mod.rs:11:1
23 |
24LL | 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
3121error[E0658]: custom inner attributes are unstable
3222 --> $DIR/inner-attr-file-mod.rs:11:1
3323 |
......@@ -38,6 +28,6 @@ LL | mod module_with_attrs;
3828 = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
3929 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
4030
41error: aborting due to 4 previous errors
31error: aborting due to 3 previous errors
4232
4333For 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.
4pub 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]
8extern crate expect_modules;
9
10#[expect_modules::expect_mod_item]
11mod module;
12
13fn check() {
14 module::hello();
15}
16
17#[expect_modules::expect_mods_attr]
18mod 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]
29fn foo() {
30 #[path = "module.rs"]
31 mod attr_outlined;
32 mod attr_inline {}
33 attr_outlined::hello();
34}
35
36#[derive(expect_modules::ExpectModsDerive)]
37struct Foo(
38 [u8; {
39 #[path = "module.rs"]
40 mod derive_outlined;
41 mod derive_inline {}
42 derive_outlined::hello();
43 0
44 }],
45);
46
47fn main() {}
tests/ui/proc-macro/unsafe-mod.rs-2
......@@ -1,8 +1,6 @@
11//@ run-pass
22//@ proc-macro: macro-only-syntax.rs
33
4#![feature(proc_macro_hygiene)]
5
64extern crate macro_only_syntax;
75
86#[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
13#![feature(reborrow)]
24
35use std::marker::{CoerceShared, Reborrow};
......@@ -25,7 +27,6 @@ struct AliasRef<'a> {
2527}
2628
2729impl<'a> CoerceShared<AliasRef<'a>> for AliasMut<'a> {}
28//~^ ERROR
2930
3031struct InnerLifetimeMut<'a> {
3132 value: &'a mut &'static (),
tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr deleted-9
......@@ -1,9 +0,0 @@
1error[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 |
4LL | 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
7error: aborting due to 1 previous error
8
9For 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)]
10use std::marker::{CoerceShared, Reborrow};
11
12struct NonParam;
13
14trait HasAssoc<'a> {
15 type Assoc;
16}
17
18struct A;
19impl<'a> HasAssoc<'a> for A {
20 type Assoc = &'a mut NonParam;
21}
22type MutAlias<'a> = <A as HasAssoc<'a>>::Assoc;
23
24struct B;
25impl<'a> HasAssoc<'a> for B {
26 type Assoc = &'a NonParam;
27}
28type RefAlias<'a> = <B as HasAssoc<'a>>::Assoc;
29
30struct CustomMut<'a>(MutAlias<'a>);
31struct CustomRef<'a>(RefAlias<'a>);
32
33struct C;
34impl<'a> HasAssoc<'a> for C {
35 type Assoc = CustomMut<'a>;
36}
37type CustomMutAlias<'a> = <C as HasAssoc<'a>>::Assoc;
38
39struct D;
40impl<'a> HasAssoc<'a> for D {
41 type Assoc = CustomRef<'a>;
42}
43type CustomRefAlias<'a> = <D as HasAssoc<'a>>::Assoc;
44
45impl<'a> Clone for CustomRef<'a> {
46 fn clone(&self) -> Self {
47 Self(self.0)
48 }
49}
50impl<'a> Copy for CustomRef<'a> {}
51
52
53impl<'a> Reborrow for CustomMut<'a> {}
54impl<'a> CoerceShared<CustomRefAlias<'a>> for CustomMutAlias<'a> {}
55
56fn 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
16#![feature(type_alias_impl_trait)]
27#![feature(auto_traits)]
38
......@@ -5,7 +10,6 @@ type Alias = (impl Sized, u8);
510
611auto trait Trait {}
712impl Trait for Alias {}
8//~^ ERROR traits with a default impl, like `Trait`, cannot be implemented for type alias `Alias`
913
1014#[define_opaque(Alias)]
1115fn _def() -> Alias {
tests/ui/type-alias-impl-trait/impl_for_weak_alias.stderr deleted-11
......@@ -1,11 +0,0 @@
1error[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 |
4LL | 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
9error: aborting due to 1 previous error
10
11For more information about this error, try `rustc --explain E0321`.