From 8f3f66637134deead86ef55e8cf8047e8c3b552a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 17 Feb 2014 18:52:11 +1300 Subject: [PATCH] Forbid use of generics with foreign functions. Closes #10353. --- src/librustc/middle/typeck/collect.rs | 204 +++++++++++++----------- src/test/compile-fail/generic-extern.rs | 15 ++ 2 files changed, 125 insertions(+), 94 deletions(-) create mode 100644 src/test/compile-fail/generic-extern.rs diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 28100717e71c5..eff8680f27cbf 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -552,110 +552,126 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, } } +fn ensure_generics_abi(ccx: &CrateCtxt, + span: Span, + abis: AbiSet, + generics: &ast::Generics) { + if generics.ty_params.len() > 0 && + !(abis.is_rust() || abis.is_intrinsic()) { + ccx.tcx.sess.span_err(span, + "foreign functions may not use type parameters"); + } +} + pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); match it.node { - // These don't define types. - ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {} - ast::ItemEnum(ref enum_definition, ref generics) => { - ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); - get_enum_variant_types(ccx, - tpt.ty, - enum_definition.variants, - generics); - } - ast::ItemImpl(ref generics, ref opt_trait_ref, selfty, ref ms) => { - let i_ty_generics = ty_generics(ccx, generics, 0); - let selfty = ccx.to_ty(&ExplicitRscope, selfty); - write_ty_to_tcx(tcx, it.id, selfty); + // These don't define types. + ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {} + ast::ItemEnum(ref enum_definition, ref generics) => { + ensure_no_ty_param_bounds(ccx, it.span, generics, "enumeration"); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + get_enum_variant_types(ccx, + tpt.ty, + enum_definition.variants, + generics); + }, + ast::ItemImpl(ref generics, ref opt_trait_ref, selfty, ref ms) => { + let i_ty_generics = ty_generics(ccx, generics, 0); + let selfty = ccx.to_ty(&ExplicitRscope, selfty); + write_ty_to_tcx(tcx, it.id, selfty); - { - let mut tcache = tcx.tcache.borrow_mut(); - tcache.get().insert(local_def(it.id), - ty_param_bounds_and_ty { - generics: i_ty_generics.clone(), - ty: selfty}); - } + { + let mut tcache = tcx.tcache.borrow_mut(); + tcache.get().insert(local_def(it.id), + ty_param_bounds_and_ty { + generics: i_ty_generics.clone(), + ty: selfty}); + } - // If there is a trait reference, treat the methods as always public. - // This is to work around some incorrect behavior in privacy checking: - // when the method belongs to a trait, it should acquire the privacy - // from the trait, not the impl. Forcing the visibility to be public - // makes things sorta work. - let parent_visibility = if opt_trait_ref.is_some() { - ast::Public - } else { - it.vis - }; + // If there is a trait reference, treat the methods as always public. + // This is to work around some incorrect behavior in privacy checking: + // when the method belongs to a trait, it should acquire the privacy + // from the trait, not the impl. Forcing the visibility to be public + // makes things sorta work. + let parent_visibility = if opt_trait_ref.is_some() { + ast::Public + } else { + it.vis + }; - convert_methods(ccx, - ImplContainer(local_def(it.id)), - *ms, - selfty, - &i_ty_generics, - generics, - parent_visibility); - - for trait_ref in opt_trait_ref.iter() { - let trait_ref = instantiate_trait_ref(ccx, trait_ref, selfty); - - // Prevent the builtin kind traits from being manually implemented. - if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_some() { - tcx.sess.span_err(it.span, - "cannot provide an explicit implementation \ - for a builtin kind"); + convert_methods(ccx, + ImplContainer(local_def(it.id)), + *ms, + selfty, + &i_ty_generics, + generics, + parent_visibility); + + for trait_ref in opt_trait_ref.iter() { + let trait_ref = instantiate_trait_ref(ccx, trait_ref, selfty); + + // Prevent the builtin kind traits from being manually implemented. + if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_some() { + tcx.sess.span_err(it.span, + "cannot provide an explicit implementation \ + for a builtin kind"); + } } - } - } - ast::ItemTrait(ref generics, _, ref trait_methods) => { - let trait_def = trait_def_of_item(ccx, it); - - // Run convert_methods on the provided methods. - let (_, provided_methods) = - split_trait_methods(*trait_methods); - let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); - convert_methods(ccx, - TraitContainer(local_def(it.id)), - provided_methods, - untransformed_rcvr_ty, - &trait_def.generics, - generics, - it.vis); - - // We need to do this *after* converting methods, since - // convert_methods produces a tcache entry that is wrong for - // static trait methods. This is somewhat unfortunate. - ensure_trait_methods(ccx, it.id); - } - ast::ItemStruct(struct_def, ref generics) => { - ensure_no_ty_param_bounds(ccx, it.span, generics, "structure"); - - // Write the class type - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); + }, + ast::ItemTrait(ref generics, _, ref trait_methods) => { + let trait_def = trait_def_of_item(ccx, it); + + // Run convert_methods on the provided methods. + let (_, provided_methods) = + split_trait_methods(*trait_methods); + let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); + convert_methods(ccx, + TraitContainer(local_def(it.id)), + provided_methods, + untransformed_rcvr_ty, + &trait_def.generics, + generics, + it.vis); + + // We need to do this *after* converting methods, since + // convert_methods produces a tcache entry that is wrong for + // static trait methods. This is somewhat unfortunate. + ensure_trait_methods(ccx, it.id); + }, + ast::ItemStruct(struct_def, ref generics) => { + ensure_no_ty_param_bounds(ccx, it.span, generics, "structure"); + + // Write the class type + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); - { - let mut tcache = tcx.tcache.borrow_mut(); - tcache.get().insert(local_def(it.id), tpt.clone()); - } + { + let mut tcache = tcx.tcache.borrow_mut(); + tcache.get().insert(local_def(it.id), tpt.clone()); + } - convert_struct(ccx, struct_def, tpt, it.id); - } - ast::ItemTy(_, ref generics) => { - ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); - } - _ => { - // This call populates the type cache with the converted type - // of the item in passing. All we have to do here is to write - // it into the node type table. - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); - } + convert_struct(ccx, struct_def, tpt, it.id); + }, + ast::ItemTy(_, ref generics) => { + ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + }, + ast::ItemFn(_, _, abi, ref generics, _) => { + ensure_generics_abi(ccx, it.span, abi, generics); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + }, + _ => { + // This call populates the type cache with the converted type + // of the item in passing. All we have to do here is to write + // it into the node type table. + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + }, } } diff --git a/src/test/compile-fail/generic-extern.rs b/src/test/compile-fail/generic-extern.rs new file mode 100644 index 0000000000000..ce8099d64a0f1 --- /dev/null +++ b/src/test/compile-fail/generic-extern.rs @@ -0,0 +1,15 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern "C" fn foo() {} //~ERROR foreign functions may not use type parameters + +fn main() { + let _ = foo::; +}