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_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_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/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`. 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(); +}