From 4559e61dd7c44705ca2ed62e4d93fe94ab1010f6 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 1 Apr 2024 11:27:48 +0200 Subject: [PATCH 1/7] Test `#[unix_sigpipe = "inherit"]` with both `SIG_DFL` and `SIG_IGN` Add a test that fails if `#[unix_sigpipe = "inherit"]` wrongly results in `SIGPIPE` being `SIG_DFL` if the parent has `SIG_IGN`. We have no current test for this particular case. --- .../auxiliary/assert-inherit-sig_dfl.rs | 8 +++++ .../auxiliary/assert-inherit-sig_ign.rs | 8 +++++ .../unix_sigpipe/unix_sigpipe-inherit.rs | 31 ++++++++++++++----- 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs create mode 100644 tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs new file mode 100644 index 0000000000000..7f95fa7ebbece --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_dfl.rs @@ -0,0 +1,8 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs + +#![feature(unix_sigpipe)] + +#[unix_sigpipe = "inherit"] +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +} diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs new file mode 100644 index 0000000000000..d96e8b8ef8436 --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-inherit-sig_ign.rs @@ -0,0 +1,8 @@ +//@ aux-crate: sigpipe_utils=sigpipe-utils.rs + +#![feature(unix_sigpipe)] + +#[unix_sigpipe = "inherit"] +fn main() { + sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore); +} diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs index db3407a7d55fc..694fa460e9bb4 100644 --- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs +++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs @@ -1,14 +1,29 @@ +//@ ignore-cross-compile because aux-bin does not yet support it +//@ only-unix because SIGPIPE is a unix thing +//@ aux-bin: assert-inherit-sig_dfl.rs +//@ aux-bin: assert-inherit-sig_ign.rs //@ run-pass -//@ aux-build:sigpipe-utils.rs -#![feature(unix_sigpipe)] +#![feature(rustc_private, unix_sigpipe)] -#[unix_sigpipe = "inherit"] +extern crate libc; + +// By default the Rust runtime resets SIGPIPE to SIG_DFL before exec:ing child +// processes so opt-out of that with `#[unix_sigpipe = "sig_dfl"]`. See +// https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L359-L384 +#[unix_sigpipe = "sig_dfl"] fn main() { - extern crate sigpipe_utils; + // First expect SIG_DFL in a child process with #[unix_sigpipe = "inherit"]. + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_dfl"); + + // With SIG_IGN we expect #[unix_sigpipe = "inherit"] to also get SIG_IGN. + unsafe { + libc::signal(libc::SIGPIPE, libc::SIG_IGN); + } + assert_inherit_sigpipe_disposition("auxiliary/bin/assert-inherit-sig_ign"); +} - // #[unix_sigpipe = "inherit"] is active, so SIGPIPE shall NOT be ignored, - // instead the default handler shall be installed. (We assume that the - // process that runs these tests have the default handler.) - sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); +fn assert_inherit_sigpipe_disposition(aux_bin: &str) { + let mut cmd = std::process::Command::new(aux_bin); + assert!(cmd.status().unwrap().success()); } From a21c2d870470b07d559faeaf88e7d16c765fc6ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Apr 2024 09:32:35 +0200 Subject: [PATCH 2/7] windows fill_utf16_buf: explain the expected return value --- library/std/src/sys/pal/windows/mod.rs | 17 ++++++++++++----- library/std/src/sys/pal/windows/os.rs | 2 ++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index b49585599cb32..ff41f6e77be7a 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -201,14 +201,21 @@ pub fn to_u16s>(s: S) -> crate::io::Result> { // currently reside in the buffer. This function is an abstraction over these // functions by making them easier to call. // -// The first callback, `f1`, is yielded a (pointer, len) pair which can be +// The first callback, `f1`, is passed a (pointer, len) pair which can be // passed to a syscall. The `ptr` is valid for `len` items (u16 in this case). -// The closure is expected to return what the syscall returns which will be -// interpreted by this function to determine if the syscall needs to be invoked -// again (with more buffer space). +// The closure is expected to: +// - On success, return the actual length of the written data *without* the null terminator. +// This can be 0. In this case the last_error must be left unchanged. +// - On insufficient buffer space, +// - either return the required length *with* the null terminator, +// - or set the last-error to ERROR_INSUFFICIENT_BUFFER and return `len`. +// - On other failure, return 0 and set last_error. +// +// This is how most but not all syscalls indicate the required buffer space. +// Other syscalls may need translation to match this protocol. // // Once the syscall has completed (errors bail out early) the second closure is -// yielded the data which has been read from the syscall. The return value +// passed the data which has been read from the syscall. The return value // from this closure is then the return value of the function. pub fn fill_utf16_buf(mut f1: F1, f2: F2) -> crate::io::Result where diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 374c9845ea4bb..64d8b72aed282 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -326,6 +326,8 @@ fn home_dir_crt() -> Option { super::fill_utf16_buf( |buf, mut sz| { + // GetUserProfileDirectoryW does not quite use the usual protocol for + // negotiating the buffer size, so we have to translate. match c::GetUserProfileDirectoryW( ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN), buf, From 99b635eafa372d3b8522e978262095f60a8b4e56 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 14 Mar 2024 11:41:38 +0300 Subject: [PATCH 3/7] delegation: Support renaming --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/mut_visit.rs | 10 ++++++++-- compiler/rustc_ast/src/visit.rs | 6 ++++-- compiler/rustc_parse/src/parser/item.rs | 10 +++++----- tests/ui/delegation/rename.rs | 20 ++++++++++++++++++++ 5 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 tests/ui/delegation/rename.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index bddb50568d41b..727c6bc82fef9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3112,6 +3112,7 @@ pub struct Delegation { /// Path resolution id. pub id: NodeId, pub qself: Option>, + pub rename: Option, pub path: Path, pub body: Option>, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c4e49d7dbea44..7dbfb7c736454 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1149,10 +1149,13 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { } ItemKind::MacCall(m) => vis.visit_mac_call(m), ItemKind::MacroDef(def) => vis.visit_macro_def(def), - ItemKind::Delegation(box Delegation { id, qself, path, body }) => { + ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { vis.visit_id(id); vis.visit_qself(qself); vis.visit_path(path); + if let Some(rename) = rename { + vis.visit_ident(rename); + } if let Some(body) = body { vis.visit_block(body); } @@ -1195,10 +1198,13 @@ pub fn noop_flat_map_assoc_item( visit_opt(ty, |ty| visitor.visit_ty(ty)); } AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), - AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => { + AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { visitor.visit_id(id); visitor.visit_qself(qself); visitor.visit_path(path); + if let Some(rename) = rename { + visitor.visit_ident(rename); + } if let Some(body) = body { visitor.visit_block(body); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 968d10ad4872c..d9740928f8d67 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -382,11 +382,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) -> V::Resu } ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)), - ItemKind::Delegation(box Delegation { id, qself, path, body }) => { + ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { if let Some(qself) = qself { try_visit!(visitor.visit_ty(&qself.ty)); } try_visit!(visitor.visit_path(path, *id)); + visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } } @@ -782,11 +783,12 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>( AssocItemKind::MacCall(mac) => { try_visit!(visitor.visit_mac_call(mac)); } - AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => { + AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { if let Some(qself) = qself { try_visit!(visitor.visit_ty(&qself.ty)); } try_visit!(visitor.visit_path(path, *id)); + visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 84ecd0a0de54f..ed51710564a42 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -686,6 +686,8 @@ impl<'a> Parser<'a> { (None, self.parse_path(PathStyle::Expr)?) }; + let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None }; + let body = if self.check(&token::OpenDelim(Delimiter::Brace)) { Some(self.parse_block()?) } else { @@ -695,11 +697,9 @@ impl<'a> Parser<'a> { let span = span.to(self.prev_token.span); self.psess.gated_spans.gate(sym::fn_delegation, span); - let ident = path.segments.last().map(|seg| seg.ident).unwrap_or(Ident::empty()); - Ok(( - ident, - ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, body })), - )) + let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); + let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body }; + Ok((ident, ItemKind::Delegation(Box::new(deleg)))) } fn parse_item_list( diff --git a/tests/ui/delegation/rename.rs b/tests/ui/delegation/rename.rs new file mode 100644 index 0000000000000..f4b3da76c56c7 --- /dev/null +++ b/tests/ui/delegation/rename.rs @@ -0,0 +1,20 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn a() {} +} + +reuse to_reuse::a as b; + +struct S; +impl S { + reuse to_reuse::a as b; +} + +fn main() { + b(); + S::b(); +} From 7b7c26f09bbc292da8600e8dfaa454de63ada886 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 14 Mar 2024 15:42:14 +0300 Subject: [PATCH 4/7] delegation: Support async, const, extern "ABI" and C-variadic functions Also allow `impl Trait` in delegated functions. The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created. --- compiler/rustc_ast_lowering/src/delegation.rs | 117 ++++++++++++------ compiler/rustc_ast_lowering/src/item.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 28 ----- compiler/rustc_middle/src/ty/mod.rs | 13 +- compiler/rustc_resolve/src/late.rs | 14 ++- .../rustc_resolve/src/late/diagnostics.rs | 7 +- compiler/rustc_resolve/src/lib.rs | 16 +-- .../ui/delegation/auxiliary/fn-header-aux.rs | 9 ++ tests/ui/delegation/fn-header.rs | 57 +++++++++ tests/ui/delegation/impl-trait.rs | 27 ++++ tests/ui/delegation/not-supported.rs | 30 ++--- tests/ui/delegation/not-supported.stderr | 75 +++++------ 12 files changed, 244 insertions(+), 151 deletions(-) create mode 100644 tests/ui/delegation/auxiliary/fn-header-aux.rs create mode 100644 tests/ui/delegation/fn-header.rs create mode 100644 tests/ui/delegation/impl-trait.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index f4d5e71badebb..a1e5c275c189c 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -49,7 +49,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; -use rustc_middle::ty::ResolverAstLowering; +use rustc_middle::ty::{Asyncness, ResolverAstLowering}; use rustc_span::{symbol::Ident, Span}; use rustc_target::spec::abi; use std::iter; @@ -67,7 +67,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return false; }; if let Some(local_sig_id) = sig_id.as_local() { - self.resolver.has_self.contains(&local_sig_id) + self.resolver.delegation_fn_sigs[&local_sig_id].has_self } else { match self.tcx.def_kind(sig_id) { DefKind::Fn => false, @@ -82,13 +82,14 @@ impl<'hir> LoweringContext<'_, 'hir> { delegation: &Delegation, item_id: NodeId, ) -> DelegationResults<'hir> { - let span = delegation.path.segments.last().unwrap().ident.span; + let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span); match sig_id { Ok(sig_id) => { - let decl = self.lower_delegation_decl(sig_id, span); - let sig = self.lower_delegation_sig(span, decl); - let body_id = self.lower_delegation_body(sig.decl, delegation); + let (param_count, c_variadic) = self.param_count(sig_id); + let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span); + let sig = self.lower_delegation_sig(sig_id, decl, span); + let body_id = self.lower_delegation_body(delegation, param_count, span); let generics = self.lower_delegation_generics(span); DelegationResults { body_id, sig, generics } @@ -123,34 +124,47 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } + // Function parameter count, including C variadic `...` if present. + fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) { + if let Some(local_sig_id) = sig_id.as_local() { + // Map may be filled incorrectly due to recursive delegation. + // Error will be emmited later during HIR ty lowering. + match self.resolver.delegation_fn_sigs.get(&local_sig_id) { + Some(sig) => (sig.param_count, sig.c_variadic), + None => (0, false), + } + } else { + let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); + (sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic) + } + } + fn lower_delegation_decl( &mut self, sig_id: DefId, - param_span: Span, + param_count: usize, + c_variadic: bool, + span: Span, ) -> &'hir hir::FnDecl<'hir> { - let args_count = if let Some(local_sig_id) = sig_id.as_local() { - // Map may be filled incorrectly due to recursive delegation. - // Error will be emitted later during HIR ty lowering. - self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default() - } else { - self.tcx.fn_arg_names(sig_id).len() - }; - let inputs = self.arena.alloc_from_iter((0..args_count).map(|arg| hir::Ty { + // The last parameter in C variadic functions is skipped in the signature, + // like during regular lowering. + let decl_param_count = param_count - c_variadic as usize; + let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)), - span: self.lower_span(param_span), + span, })); let output = self.arena.alloc(hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output), - span: self.lower_span(param_span), + span, }); self.arena.alloc(hir::FnDecl { inputs, output: hir::FnRetTy::Return(output), - c_variadic: false, + c_variadic, lifetime_elision_allowed: true, implicit_self: hir::ImplicitSelfKind::None, }) @@ -158,35 +172,45 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_delegation_sig( &mut self, - span: Span, + sig_id: DefId, decl: &'hir hir::FnDecl<'hir>, + span: Span, ) -> hir::FnSig<'hir> { - hir::FnSig { - decl, - header: hir::FnHeader { - unsafety: hir::Unsafety::Normal, - constness: hir::Constness::NotConst, - asyncness: hir::IsAsync::NotAsync, - abi: abi::Abi::Rust, - }, - span: self.lower_span(span), - } + let header = if let Some(local_sig_id) = sig_id.as_local() { + match self.resolver.delegation_fn_sigs.get(&local_sig_id) { + Some(sig) => self.lower_fn_header(sig.header), + None => self.generate_header_error(), + } + } else { + let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder(); + let asyncness = match self.tcx.asyncness(sig_id) { + Asyncness::Yes => hir::IsAsync::Async(span), + Asyncness::No => hir::IsAsync::NotAsync, + }; + hir::FnHeader { + unsafety: sig.unsafety, + constness: self.tcx.constness(sig_id), + asyncness, + abi: sig.abi, + } + }; + hir::FnSig { decl, header, span } } - fn generate_param(&mut self, ty: &'hir hir::Ty<'hir>) -> (hir::Param<'hir>, NodeId) { + fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) { let pat_node_id = self.next_node_id(); let pat_id = self.lower_node_id(pat_node_id); let pat = self.arena.alloc(hir::Pat { hir_id: pat_id, kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None), - span: ty.span, + span, default_binding_modes: false, }); - (hir::Param { hir_id: self.next_id(), pat, ty_span: ty.span, span: ty.span }, pat_node_id) + (hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id) } - fn generate_arg(&mut self, ty: &'hir hir::Ty<'hir>, param_id: HirId) -> hir::Expr<'hir> { + fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> { let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment { ident: Ident::empty(), hir_id: self.next_id(), @@ -195,20 +219,20 @@ impl<'hir> LoweringContext<'_, 'hir> { infer_args: false, })); - let path = - self.arena.alloc(hir::Path { span: ty.span, res: Res::Local(param_id), segments }); + let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); hir::Expr { hir_id: self.next_id(), kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), - span: ty.span, + span, } } fn lower_delegation_body( &mut self, - decl: &'hir hir::FnDecl<'hir>, delegation: &Delegation, + param_count: usize, + span: Span, ) -> BodyId { let path = self.lower_qpath( delegation.id, @@ -224,8 +248,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut parameters: Vec> = Vec::new(); let mut args: Vec> = Vec::new(); - for (idx, param_ty) in decl.inputs.iter().enumerate() { - let (param, pat_node_id) = this.generate_param(param_ty); + for idx in 0..param_count { + let (param, pat_node_id) = this.generate_param(span); parameters.push(param); let arg = if let Some(block) = block @@ -245,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } else { let pat_hir_id = this.lower_node_id(pat_node_id); - this.generate_arg(param_ty, pat_hir_id) + this.generate_arg(pat_hir_id, span) }; args.push(arg); } @@ -304,7 +328,9 @@ impl<'hir> LoweringContext<'_, 'hir> { implicit_self: hir::ImplicitSelfKind::None, }); - let sig = self.lower_delegation_sig(span, decl); + let header = self.generate_header_error(); + let sig = hir::FnSig { decl, header, span }; + let body_id = self.lower_body(|this| { let expr = hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span }; @@ -312,6 +338,15 @@ impl<'hir> LoweringContext<'_, 'hir> { }); DelegationResults { generics, body_id, sig } } + + fn generate_header_error(&self) -> hir::FnHeader { + hir::FnHeader { + unsafety: hir::Unsafety::Normal, + constness: hir::Constness::NotConst, + asyncness: hir::IsAsync::NotAsync, + abi: abi::Abi::Rust, + } + } } struct SelfResolver<'a> { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e4c633aa324a8..1a1c50018ac52 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1344,7 +1344,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } - fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { + pub(super) fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind { hir::IsAsync::Async(span) } else { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4a0df6cf7b86f..63da27246a2af 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1964,11 +1964,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { try_emit("recursive delegation"); } - let sig = self.tcx().fn_sig(sig_id).instantiate_identity(); - if sig.output().has_opaque_types() { - try_emit("delegation to a function with opaque type"); - } - let sig_generics = self.tcx().generics_of(sig_id); let parent = self.tcx().parent(self.item_def_id()); let parent_generics = self.tcx().generics_of(parent); @@ -1991,29 +1986,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { try_emit("delegation to a trait method from a free function"); } - if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes { - try_emit("delegation to async functions"); - } - - if self.tcx().constness(sig_id) == hir::Constness::Const { - try_emit("delegation to const functions"); - } - - if sig.c_variadic() { - try_emit("delegation to variadic functions"); - // variadic functions are also `unsafe` and `extern "C"`. - // Do not emit same error multiple times. - return error_occured; - } - - if let hir::Unsafety::Unsafe = sig.unsafety() { - try_emit("delegation to unsafe functions"); - } - - if abi::Abi::Rust != sig.abi() { - try_emit("delegation to non Rust ABI functions"); - } - error_occured } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cc026e349d74e..cda332aee5647 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -45,7 +45,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; @@ -224,8 +224,15 @@ pub struct ResolverAstLowering { pub lint_buffer: Steal, /// Information about functions signatures for delegation items expansion - pub has_self: LocalDefIdSet, - pub fn_parameter_counts: LocalDefIdMap, + pub delegation_fn_sigs: LocalDefIdMap, +} + +#[derive(Debug)] +pub struct DelegationFnSig { + pub header: ast::FnHeader, + pub param_count: usize, + pub has_self: bool, + pub c_variadic: bool, } #[derive(Clone, Copy, Debug)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c877ae5e21f48..292af43b602e0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,6 +21,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; +use rustc_middle::ty::DelegationFnSig; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; @@ -4749,12 +4750,13 @@ struct ItemInfoCollector<'a, 'b, 'tcx> { impl ItemInfoCollector<'_, '_, '_> { fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) { - let def_id = self.r.local_def_id(id); - self.r.fn_parameter_counts.insert(def_id, sig.decl.inputs.len()); - - if sig.decl.has_self() { - self.r.has_self.insert(def_id); - } + let sig = DelegationFnSig { + header: sig.header, + param_count: sig.decl.inputs.len(), + has_self: sig.decl.has_self(), + c_variadic: sig.decl.c_variadic(), + }; + self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d79c638fa0789..64451030adf0f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2039,7 +2039,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called }, ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType, ast::AssocItemKind::Delegation(..) - if self.r.has_self.contains(&self.r.local_def_id(assoc_item.id)) => + if self.r.delegation_fn_sigs[&self.r.local_def_id(assoc_item.id)] + .has_self => { AssocSuggestion::MethodWithSelf { called } } @@ -2062,7 +2063,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if filter_fn(res) { let def_id = res.def_id(); let has_self = match def_id.as_local() { - Some(def_id) => self.r.has_self.contains(&def_id), + Some(def_id) => { + self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self) + } None => self .r .tcx diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b5b6d899cc58e..e07c3247d07ae 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -43,7 +43,7 @@ use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::NonMacroAttrKind; use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{PrimTy, TraitCandidate}; use rustc_index::IndexVec; @@ -52,8 +52,8 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt, TyCtxtFeed}; -use rustc_middle::ty::{Feed, ResolverGlobalCtxt, ResolverOutputs}; +use rustc_middle::ty::{self, DelegationFnSig, Feed, MainDefinition, RegisteredTools}; +use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::LintBuffer; @@ -992,7 +992,6 @@ pub struct Resolver<'a, 'tcx> { extern_prelude: FxHashMap>, /// N.B., this is used only for better diagnostics, not name resolution itself. - has_self: LocalDefIdSet, field_def_ids: LocalDefIdMap<&'tcx [DefId]>, /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. @@ -1149,8 +1148,7 @@ pub struct Resolver<'a, 'tcx> { legacy_const_generic_args: FxHashMap>>, /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap, - /// Amount of parameters for each function in the crate. - fn_parameter_counts: LocalDefIdMap, + delegation_fn_sigs: LocalDefIdMap, main_def: Option, trait_impls: FxIndexMap>, @@ -1399,7 +1397,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { prelude: None, extern_prelude, - has_self: Default::default(), field_def_ids: Default::default(), field_visibility_spans: FxHashMap::default(), @@ -1508,7 +1505,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { doc_link_resolutions: Default::default(), doc_link_traits_in_scope: Default::default(), all_macro_rules: Default::default(), - fn_parameter_counts: Default::default(), + delegation_fn_sigs: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1621,8 +1618,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), - has_self: self.has_self, - fn_parameter_counts: self.fn_parameter_counts, + delegation_fn_sigs: self.delegation_fn_sigs, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/tests/ui/delegation/auxiliary/fn-header-aux.rs b/tests/ui/delegation/auxiliary/fn-header-aux.rs new file mode 100644 index 0000000000000..d26209a4f789f --- /dev/null +++ b/tests/ui/delegation/auxiliary/fn-header-aux.rs @@ -0,0 +1,9 @@ +//@ edition:2018 + +#![feature(c_variadic)] + +pub unsafe fn unsafe_fn_extern() {} +pub extern "C" fn extern_fn_extern() {} +pub unsafe extern "C" fn variadic_fn_extern(n: usize, mut args: ...) {} +pub const fn const_fn_extern() {} +pub async fn async_fn_extern() {} diff --git a/tests/ui/delegation/fn-header.rs b/tests/ui/delegation/fn-header.rs new file mode 100644 index 0000000000000..db20e1058e061 --- /dev/null +++ b/tests/ui/delegation/fn-header.rs @@ -0,0 +1,57 @@ +//@ check-pass +//@ edition:2018 +//@ aux-crate:fn_header_aux=fn-header-aux.rs + +#![feature(c_variadic)] +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![deny(unused_unsafe)] + +mod to_reuse { + pub unsafe fn unsafe_fn() {} + pub extern "C" fn extern_fn() {} + pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} + pub const fn const_fn() {} + pub async fn async_fn() {} +} + +reuse to_reuse::unsafe_fn; +reuse to_reuse::extern_fn; +reuse to_reuse::variadic_fn; +reuse to_reuse::const_fn; +reuse to_reuse::async_fn; + +reuse fn_header_aux::unsafe_fn_extern; +reuse fn_header_aux::extern_fn_extern; +reuse fn_header_aux::variadic_fn_extern; +reuse fn_header_aux::const_fn_extern; +reuse fn_header_aux::async_fn_extern; + +const fn const_check() { + const_fn(); + const_fn_extern(); +} + +async fn async_check() { + async_fn().await; + async_fn_extern().await; +} + +fn main() { + unsafe { + unsafe_fn(); + unsafe_fn_extern(); + } + extern_fn(); + extern_fn_extern(); + let _: extern "C" fn() = extern_fn; + let _: extern "C" fn() = extern_fn_extern; + unsafe { + variadic_fn(0); + variadic_fn(0, 1); + variadic_fn_extern(0); + variadic_fn_extern(0, 1); + } + let _: unsafe extern "C" fn(usize, ...) = variadic_fn; + let _: unsafe extern "C" fn(usize, ...) = variadic_fn_extern; +} diff --git a/tests/ui/delegation/impl-trait.rs b/tests/ui/delegation/impl-trait.rs new file mode 100644 index 0000000000000..13df0155485c9 --- /dev/null +++ b/tests/ui/delegation/impl-trait.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse { + pub fn foo() -> impl Clone { 0 } +} + +reuse to_reuse::foo; + +trait Trait { + fn bar() -> impl Clone { 1 } +} + +struct S; +impl Trait for S {} + +impl S { + reuse to_reuse::foo; + reuse ::bar; +} + +fn main() { + foo().clone(); + ::bar().clone(); +} diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 9dccb12b57adb..5f78de97638b5 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -14,9 +14,9 @@ mod generics { fn foo3<'a: 'a>(_: &'a u32) {} reuse GenericTrait::bar; - //~^ delegation with early bound generics is not supported yet + //~^ ERROR delegation with early bound generics is not supported yet reuse GenericTrait::bar1; - //~^ delegation with early bound generics is not supported yet + //~^ ERROR delegation with early bound generics is not supported yet } struct F; @@ -73,26 +73,18 @@ mod opaque { } reuse to_reuse::opaque_arg; //~^ ERROR delegation with early bound generics is not supported yet - reuse to_reuse::opaque_ret; - //~^ ERROR delegation to a function with opaque type is not supported yet -} -mod fn_header { - mod to_reuse { - pub unsafe fn unsafe_fn() {} - pub extern "C" fn extern_fn() {} - pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} - pub const fn const_fn() {} + trait ToReuse { + fn opaque_ret() -> impl Trait { unimplemented!() } } - reuse to_reuse::unsafe_fn; - //~^ ERROR delegation to unsafe functions is not supported yet - reuse to_reuse::extern_fn; - //~^ ERROR delegation to non Rust ABI functions is not supported yet - reuse to_reuse::variadic_fn; - //~^ ERROR delegation to variadic functions is not supported yet - reuse to_reuse::const_fn; - //~^ ERROR delegation to const functions is not supported yet + // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. + impl ToReuse for u8 { + reuse to_reuse::opaque_ret; //~ ERROR cycle detected when computing type + } + impl ToReuse for u16 { + reuse ToReuse::opaque_ret; //~ ERROR cycle detected when computing type + } } mod recursive { diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index f6c49366899c1..e2cb04f977b1e 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -115,53 +115,46 @@ LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } LL | reuse to_reuse::opaque_arg; | ^^^^^^^^^^ -error: delegation to a function with opaque type is not supported yet - --> $DIR/not-supported.rs:76:21 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:83:25 | -LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } - | --------------------------------- callee defined here -... -LL | reuse to_reuse::opaque_ret; - | ^^^^^^^^^^ - -error: delegation to unsafe functions is not supported yet - --> $DIR/not-supported.rs:88:21 +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ | -LL | pub unsafe fn unsafe_fn() {} - | ------------------------- callee defined here -... -LL | reuse to_reuse::unsafe_fn; - | ^^^^^^^^^ - -error: delegation to non Rust ABI functions is not supported yet - --> $DIR/not-supported.rs:90:21 +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/not-supported.rs:83:25 | -LL | pub extern "C" fn extern_fn() {} - | ----------------------------- callee defined here -... -LL | reuse to_reuse::extern_fn; - | ^^^^^^^^^ - -error: delegation to variadic functions is not supported yet - --> $DIR/not-supported.rs:92:21 +LL | reuse to_reuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:82:5 | -LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {} - | ------------------------------------------------------------- callee defined here -... -LL | reuse to_reuse::variadic_fn; - | ^^^^^^^^^^^ +LL | impl ToReuse for u8 { + | ^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: delegation to const functions is not supported yet - --> $DIR/not-supported.rs:94:21 +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:86:24 | -LL | pub const fn const_fn() {} - | ----------------------- callee defined here -... -LL | reuse to_reuse::const_fn; - | ^^^^^^^^ +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/not-supported.rs:86:24 + | +LL | reuse ToReuse::opaque_ret; + | ^^^^^^^^^^ + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:85:5 + | +LL | impl ToReuse for u16 { + | ^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/not-supported.rs:107:22 + --> $DIR/not-supported.rs:99:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -169,7 +162,7 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: aborting due to 19 previous errors +error: aborting due to 16 previous errors -Some errors have detailed explanations: E0049, E0195. +Some errors have detailed explanations: E0049, E0195, E0391. For more information about an error, try `rustc --explain E0049`. From bcc4469c2b4d75bd52f23d404e9c4b3561372b2a Mon Sep 17 00:00:00 2001 From: "Christopher B. Speir" Date: Tue, 23 Apr 2024 14:38:29 -0500 Subject: [PATCH 5/7] Add diagnostic item for std::iter::Enumerate --- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/iter/adapters/enumerate.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8abf42e2c1392..99591b5e1440b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -192,6 +192,7 @@ symbols! { Duration, Encodable, Encoder, + Enumerate, Eq, Equal, Err, diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index ef46040f0a703..7adbabf69e490 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -15,6 +15,7 @@ use crate::ops::Try; #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Enumerate")] pub struct Enumerate { iter: I, count: usize, From ca4a18fafca1dc19eb73b1dc28d050153aa8286e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Apr 2024 14:14:15 +0000 Subject: [PATCH 6/7] Add some FnDef LUB coercion tests --- tests/ui/fn/fn_def_coercion.rs | 58 ++++++++ tests/ui/fn/fn_def_coercion.stderr | 154 ++++++++++++++++++++++ tests/ui/fn/fn_def_opaque_coercion.rs | 67 ++++++++++ tests/ui/fn/fn_def_opaque_coercion.stderr | 42 ++++++ 4 files changed, 321 insertions(+) create mode 100644 tests/ui/fn/fn_def_coercion.rs create mode 100644 tests/ui/fn/fn_def_coercion.stderr create mode 100644 tests/ui/fn/fn_def_opaque_coercion.rs create mode 100644 tests/ui/fn/fn_def_opaque_coercion.stderr diff --git a/tests/ui/fn/fn_def_coercion.rs b/tests/ui/fn/fn_def_coercion.rs new file mode 100644 index 0000000000000..313be6f28cdcc --- /dev/null +++ b/tests/ui/fn/fn_def_coercion.rs @@ -0,0 +1,58 @@ +//! Test that coercing between function items of the same function, +//! but with different generic args succeeds in typeck, but then fails +//! in borrowck when the lifetimes can't actually be merged. + +fn foo(t: T) -> T { + t +} + +fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let mut x = foo::<&'a ()>; //~ ERROR: lifetime may not live long enough + x = foo::<&'b ()>; //~ ERROR: lifetime may not live long enough + x = foo::<&'c ()>; + x(a); + x(b); + x(c); +} + +fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = foo::<&'c ()>; + let _: &'c () = x(a); //~ ERROR lifetime may not live long enough +} + +fn h<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = foo::<&'a ()>; + let _: &'a () = x(c); +} + +fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let mut x = foo::<&'c ()>; + x = foo::<&'b ()>; //~ ERROR lifetime may not live long enough + x = foo::<&'a ()>; //~ ERROR lifetime may not live long enough + x(a); + x(b); + x(c); +} + +fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = match true { + true => foo::<&'b ()>, //~ ERROR lifetime may not live long enough + false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough + }; + x(a); + x(b); + x(c); +} + +fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + let x = match true { + true => foo::<&'c ()>, + false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough + }; + + x(a); + x(b); //~ ERROR lifetime may not live long enough + x(c); +} + +fn main() {} diff --git a/tests/ui/fn/fn_def_coercion.stderr b/tests/ui/fn/fn_def_coercion.stderr new file mode 100644 index 0000000000000..ec4a1bde7fd61 --- /dev/null +++ b/tests/ui/fn/fn_def_coercion.stderr @@ -0,0 +1,154 @@ +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:10:17 + | +LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'a ()>; + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:11:5 + | +LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'a ()>; +LL | x = foo::<&'b ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:20:12 + | +LL | fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +LL | let x = foo::<&'c ()>; +LL | let _: &'c () = x(a); + | ^^^^^^ type annotation requires that `'a` must outlive `'c` + | + = help: consider adding the following bound: `'a: 'c` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:30:5 + | +LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let mut x = foo::<&'c ()>; +LL | x = foo::<&'b ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:31:5 + | +LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | x = foo::<&'a ()>; + | ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:39:17 + | +LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let x = match true { +LL | true => foo::<&'b ()>, + | ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:40:18 + | +LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:50:18 + | +LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'c` defined here + | | + | lifetime `'a` defined here +... +LL | false => foo::<&'a ()>, + | ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c` + | + = help: consider adding the following bound: `'a: 'c` + = note: requirement occurs because of a function pointer to `foo` + = note: the function `foo` is invariant over the parameter `T` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/fn_def_coercion.rs:54:5 + | +LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | x(b); + | ^^^^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +help: the following changes may resolve your lifetime errors + | + = help: add bound `'a: 'c` + = help: add bound `'b: 'a` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/fn/fn_def_opaque_coercion.rs b/tests/ui/fn/fn_def_opaque_coercion.rs new file mode 100644 index 0000000000000..af7f65c2e3b70 --- /dev/null +++ b/tests/ui/fn/fn_def_opaque_coercion.rs @@ -0,0 +1,67 @@ +//! Test that coercing between function items of the same function, +//! but with different args works. + +#![feature(type_alias_impl_trait)] + +fn foo(t: T) -> T { + t +} + +type F = impl Sized; + +fn f(a: F) { + let mut x = foo::; + x = foo::<()>; + x(a); + x(()); +} + +type G = impl Sized; + +fn g(a: G) { + let x = foo::<()>; + let _: () = x(a); +} + +type H = impl Sized; + +fn h(a: H) { + let x = foo::; + let _: H = x(()); +} + +type I = impl Sized; + +fn i(a: I) { + let mut x = foo::<()>; + x = foo::; + x(a); + x(()); +} + +type J = impl Sized; + +fn j(a: J) { + let x = match true { + true => foo::, + false => foo::<()>, //~ ERROR: incompatible types + }; + x(a); + x(()); +} + +fn k() -> impl Sized { + fn bind T>(_: T, f: F) -> F { + f + } + let x = match true { + true => { + let f = foo; + bind(k(), f) + } + false => foo::<()>, //~ ERROR: incompatible types + }; + todo!() +} + +fn main() {} diff --git a/tests/ui/fn/fn_def_opaque_coercion.stderr b/tests/ui/fn/fn_def_opaque_coercion.stderr new file mode 100644 index 0000000000000..521b0277eac46 --- /dev/null +++ b/tests/ui/fn/fn_def_opaque_coercion.stderr @@ -0,0 +1,42 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/fn_def_opaque_coercion.rs:47:18 + | +LL | type J = impl Sized; + | ---------- the expected opaque type +... +LL | let x = match true { + | _____________- +LL | | true => foo::, + | | -------- this is found to be of type `fn(J) -> J {foo::}` +LL | | false => foo::<()>, + | | ^^^^^^^^^ expected opaque type, found `()` +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected fn item `fn(J) -> J {foo::}` + found fn item `fn(()) {foo::<()>}` + +error[E0308]: `match` arms have incompatible types + --> $DIR/fn_def_opaque_coercion.rs:62:18 + | +LL | fn k() -> impl Sized { + | ---------- the expected opaque type +... +LL | let x = match true { + | _____________- +LL | | true => { +LL | | let f = foo; +LL | | bind(k(), f) + | | ------------ this is found to be of type `fn(impl Sized) -> impl Sized {foo::}` +LL | | } +LL | | false => foo::<()>, + | | ^^^^^^^^^ expected opaque type, found `()` +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected fn item `fn(impl Sized) -> impl Sized {foo::}` + found fn item `fn(()) {foo::<()>}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 5c55d6a128638c56f1a8cac4bff5b5d206469e63 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 11 Apr 2024 14:25:26 +0000 Subject: [PATCH 7/7] Register hidden types when equating function definitions in coercion --- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- tests/ui/fn/fn_def_opaque_coercion.rs | 8 +++-- tests/ui/fn/fn_def_opaque_coercion.stderr | 42 ----------------------- 3 files changed, 6 insertions(+), 46 deletions(-) delete mode 100644 tests/ui/fn/fn_def_opaque_coercion.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9ebb5f95f05fd..4165fa7f07d10 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // are the same function and their parameters have a LUB. match self.commit_if_ok(|_| { self.at(cause, self.param_env).lub( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, prev_ty, new_ty, ) diff --git a/tests/ui/fn/fn_def_opaque_coercion.rs b/tests/ui/fn/fn_def_opaque_coercion.rs index af7f65c2e3b70..0a8810cf4f8ac 100644 --- a/tests/ui/fn/fn_def_opaque_coercion.rs +++ b/tests/ui/fn/fn_def_opaque_coercion.rs @@ -1,5 +1,7 @@ //! Test that coercing between function items of the same function, -//! but with different args works. +//! but with different generic args works. + +//@check-pass #![feature(type_alias_impl_trait)] @@ -44,7 +46,7 @@ type J = impl Sized; fn j(a: J) { let x = match true { true => foo::, - false => foo::<()>, //~ ERROR: incompatible types + false => foo::<()>, }; x(a); x(()); @@ -59,7 +61,7 @@ fn k() -> impl Sized { let f = foo; bind(k(), f) } - false => foo::<()>, //~ ERROR: incompatible types + false => foo::<()>, }; todo!() } diff --git a/tests/ui/fn/fn_def_opaque_coercion.stderr b/tests/ui/fn/fn_def_opaque_coercion.stderr deleted file mode 100644 index 521b0277eac46..0000000000000 --- a/tests/ui/fn/fn_def_opaque_coercion.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0308]: `match` arms have incompatible types - --> $DIR/fn_def_opaque_coercion.rs:47:18 - | -LL | type J = impl Sized; - | ---------- the expected opaque type -... -LL | let x = match true { - | _____________- -LL | | true => foo::, - | | -------- this is found to be of type `fn(J) -> J {foo::}` -LL | | false => foo::<()>, - | | ^^^^^^^^^ expected opaque type, found `()` -LL | | }; - | |_____- `match` arms have incompatible types - | - = note: expected fn item `fn(J) -> J {foo::}` - found fn item `fn(()) {foo::<()>}` - -error[E0308]: `match` arms have incompatible types - --> $DIR/fn_def_opaque_coercion.rs:62:18 - | -LL | fn k() -> impl Sized { - | ---------- the expected opaque type -... -LL | let x = match true { - | _____________- -LL | | true => { -LL | | let f = foo; -LL | | bind(k(), f) - | | ------------ this is found to be of type `fn(impl Sized) -> impl Sized {foo::}` -LL | | } -LL | | false => foo::<()>, - | | ^^^^^^^^^ expected opaque type, found `()` -LL | | }; - | |_____- `match` arms have incompatible types - | - = note: expected fn item `fn(impl Sized) -> impl Sized {foo::}` - found fn item `fn(()) {foo::<()>}` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`.