about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2014-02-17 18:52:11 +1300
committerNick Cameron <ncameron@mozilla.com>2014-02-17 18:52:11 +1300
commit8f3f66637134deead86ef55e8cf8047e8c3b552a (patch)
tree998d0cdfb0cac9cfc33b18e39bf8c6bee6b8d965
parentc8489069b43191c5298f17430933b3b88fb79c3c (diff)
downloadrust-8f3f66637134deead86ef55e8cf8047e8c3b552a.tar.gz
rust-8f3f66637134deead86ef55e8cf8047e8c3b552a.zip
Forbid use of generics with foreign functions. Closes #10353.
-rw-r--r--src/librustc/middle/typeck/collect.rs204
-rw-r--r--src/test/compile-fail/generic-extern.rs15
2 files changed, 125 insertions, 94 deletions
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 28100717e71..eff8680f27c 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 00000000000..ce8099d64a0
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern "C" fn foo<T>() {}  //~ERROR foreign functions may not use type parameters
+
+fn main() {
+    let _ = foo::<int>;
+}