From 704cd648ac1160c5f02291e505697a6cf7e20945 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 6 Mar 2013 12:27:23 -0500 Subject: [PATCH] Fix a bug with region-parameterized enums etc where trans considered them to be non-monomorphic. Merely having lifetime parameters is not enough to qualify for that status. Fixes #5243. --- src/librustc/front/test.rs | 6 ++++-- src/librustc/metadata/encoder.rs | 20 ++++++++++++-------- src/librustc/middle/trans/base.rs | 12 ++++++------ src/librustc/middle/typeck/collect.rs | 2 +- src/librustc/middle/typeck/mod.rs | 2 +- src/libsyntax/ast.rs | 10 ++++++++-- src/libsyntax/print/pprust.rs | 2 +- src/test/run-pass/issue-5243.rs | 23 +++++++++++++++++++++++ 8 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/issue-5243.rs diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 294e0a4a4b5..d13993bf569 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -178,12 +178,14 @@ fn is_test_fn(i: @ast::item) -> bool { fn has_test_signature(i: @ast::item) -> bool { match &i.node { - &ast::item_fn(ref decl, _, ref tps, _) => { + &ast::item_fn(ref decl, _, ref generics, _) => { let no_output = match decl.output.node { ast::ty_nil => true, _ => false }; - decl.inputs.is_empty() && no_output && tps.is_empty() + decl.inputs.is_empty() + && no_output + && !generics.is_parameterized() } _ => false } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index c5cb6617130..1031c3a82b0 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -228,14 +228,16 @@ fn encode_type(ecx: @EncodeContext, ebml_w: writer::Encoder, typ: ty::t) { fn encode_symbol(ecx: @EncodeContext, ebml_w: writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); - let sym = match ecx.item_symbols.find(&id) { - Some(ref x) => (/*bad*/copy *x), - None => { - ecx.diag.handler().bug( - fmt!("encode_symbol: id not found %d", id)); - } - }; - ebml_w.writer.write(str::to_bytes(sym)); + match ecx.item_symbols.find(&id) { + Some(ref x) => { + debug!("encode_symbol(id=%?, str=%s)", id, *x); + ebml_w.writer.write(str::to_bytes(*x)); + } + None => { + ecx.diag.handler().bug( + fmt!("encode_symbol: id not found %d", id)); + } + } ebml_w.end_tag(); } @@ -264,6 +266,8 @@ fn encode_enum_variant_info(ecx: @EncodeContext, ebml_w: writer::Encoder, path: &[ast_map::path_elt], index: @mut ~[entry], generics: &ast::Generics) { + debug!("encode_enum_variant_info(id=%?)", id); + let mut disr_val = 0; let mut i = 0; let vi = ty::enum_variants(ecx.tcx, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 1926b2f2e5d..76eedca2131 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2079,7 +2079,7 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) { _ => fail!(~"trans_item"), }; match /*bad*/copy item.node { - ast::item_fn(ref decl, purity, ref tps, ref body) => { + ast::item_fn(ref decl, purity, ref generics, ref body) => { if purity == ast::extern_fn { let llfndecl = get_item_val(ccx, item.id); foreign::trans_foreign_fn(ccx, @@ -2087,7 +2087,7 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) { /*bad*/copy *path, ~[path_name(item.ident)]), decl, body, llfndecl, item.id); - } else if tps.is_empty() { + } else if !generics.is_type_parameterized() { let llfndecl = get_item_val(ccx, item.id); trans_fn(ccx, vec::append(/*bad*/copy *path, ~[path_name(item.ident)]), @@ -2111,8 +2111,8 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) { ast::item_mod(ref m) => { trans_mod(ccx, m); } - ast::item_enum(ref enum_definition, ref tps) => { - if tps.is_empty() { + ast::item_enum(ref enum_definition, ref generics) => { + if !generics.is_type_parameterized() { let degen = (*enum_definition).variants.len() == 1u; let vi = ty::enum_variants(ccx.tcx, local_def(item.id)); let mut i = 0; @@ -2128,8 +2128,8 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) { }; foreign::trans_foreign_mod(ccx, foreign_mod, abi); } - ast::item_struct(struct_def, tps) => { - if tps.is_empty() { + ast::item_struct(struct_def, generics) => { + if !generics.is_type_parameterized() { trans_struct_def(ccx, struct_def, path, item.id); } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 2938f25291d..95284e81003 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -861,7 +861,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) // like "foo". This is because otherwise ty_to_str will // print the name as merely "foo", as it has no way to // reconstruct the value of X. - if !generics.is_empty() { t0 } else { + if generics.is_parameterized() { t0 } else { ty::mk_with_id(tcx, t0, def_id) } }; diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index b7d60817627..9c009a09ae9 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -315,7 +315,7 @@ fn check_main_fn_ty(ccx: @mut CrateCtxt, Some(ast_map::node_item(it,_)) => { match it.node { ast::item_fn(_, _, ref ps, _) - if !ps.is_empty() => { + if ps.is_parameterized() => { tcx.sess.span_err( main_span, ~"main function is not allowed \ diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 484fff1f9de..1ec11501f33 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -161,8 +161,14 @@ pub struct Generics { } pub impl Generics { - fn is_empty(&self) -> bool { - self.lifetimes.len() + self.ty_params.len() == 0 + fn is_parameterized(&self) -> bool { + self.lifetimes.len() + self.ty_params.len() > 0 + } + fn is_lt_parameterized(&self) -> bool { + self.lifetimes.len() > 0 + } + fn is_type_parameterized(&self) -> bool { + self.ty_params.len() > 0 } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d307e3964e7..275f5a43397 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -567,7 +567,7 @@ pub fn print_item(s: @ps, &&item: @ast::item) { ast::item_impl(ref generics, opt_trait, ty, ref methods) => { head(s, visibility_qualified(item.vis, ~"impl")); - if !generics.is_empty() { + if generics.is_parameterized() { print_generics(s, generics); space(s.s); } diff --git a/src/test/run-pass/issue-5243.rs b/src/test/run-pass/issue-5243.rs new file mode 100644 index 00000000000..9af2027ee7e --- /dev/null +++ b/src/test/run-pass/issue-5243.rs @@ -0,0 +1,23 @@ +// Copyright 2012-2013 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. + +// Check that merely have lifetime parameters is not +// enough for trans to consider this as non-monomorphic, +// which led to various assertions and failures in turn. + +struct S<'self> { + v: &'self int +} + +fn f<'lt>(_s: &S<'lt>) {} + +fn main() { + f(& S { v: &42 }); +}