From cd31e6ff3987a1e0f94c64f31d6068c459126667 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 30 Dec 2014 18:30:53 +1300 Subject: [PATCH 1/2] Forbid static methods in object safe traits Closes #19949 and rust-lang/rfcs#428 [breaking change] If you have traits used with objects with static methods, you'll need to move the static methods to a different trait. --- src/librustc_typeck/check/vtable.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index ff16568aa63fc..8371247263987 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -166,11 +166,13 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, } } - /// Returns a vec of error messages. If hte vec is empty - no errors! + /// Returns a vec of error messages. If the vec is empty - no errors! /// /// There are some limitations to calling functions through an object, because (a) the self /// type is not known (that's the whole point of a trait instance, after all, to obscure the - /// self type) and (b) the call must go through a vtable and hence cannot be monomorphized. + /// self type), (b) the call must go through a vtable and hence cannot be monomorphized and + /// (c) the trait contains static methods which can't be called because we don't know the + /// concrete type. fn check_object_safety_of_method<'tcx>(tcx: &ty::ctxt<'tcx>, method: &ty::Method<'tcx>) -> Vec { @@ -185,9 +187,11 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, } ty::StaticExplicitSelfCategory => { - // Static methods are always object-safe since they - // can't be called through a trait object - return msgs + // Static methods are never object safe (reason (c)). + msgs.push(format!("cannot call a static method (`{}`) \ + through a trait object", + method_name)); + return msgs; } ty::ByReferenceExplicitSelfCategory(..) | ty::ByBoxExplicitSelfCategory => {} From 69716ef607c3410722f35e31cc6419ad142b7e02 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 30 Dec 2014 19:03:51 +1300 Subject: [PATCH 2/2] Tests --- src/test/compile-fail/trait-object-safety.rs | 26 ++++++++++++++++++++ src/test/run-pass/trait-object-safety.rs | 11 ++++----- 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/trait-object-safety.rs diff --git a/src/test/compile-fail/trait-object-safety.rs b/src/test/compile-fail/trait-object-safety.rs new file mode 100644 index 0000000000000..d594e3e17474b --- /dev/null +++ b/src/test/compile-fail/trait-object-safety.rs @@ -0,0 +1,26 @@ +// 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. + +// Check that static methods are not object-safe. + +trait Tr { + fn foo(); +} + +struct St; + +impl Tr for St { + fn foo() {} +} + +fn main() { + let _: &Tr = &St; //~ ERROR cannot convert to a trait object because trait `Tr` is not + //~^ NOTE cannot call a static method (`foo`) through a trait object +} diff --git a/src/test/run-pass/trait-object-safety.rs b/src/test/run-pass/trait-object-safety.rs index 929cb9e7f1759..ed7284a835365 100644 --- a/src/test/run-pass/trait-object-safety.rs +++ b/src/test/run-pass/trait-object-safety.rs @@ -8,20 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that object-safe methods are identified as such. Also -// acts as a regression test for #18490 +// Check that object-safe methods are identified as such. trait Tr { - // Static methods are always safe regardless of other rules - fn new() -> Self; + fn foo(&self); } struct St; impl Tr for St { - fn new() -> St { St } + fn foo(&self) {} } fn main() { - &St as &Tr; + let s: &Tr = &St; + s.foo(); }