Skip to content

Commit dc65762

Browse files
committed
auto merge of #10990 : ktt3ja/rust/method-stability, r=huonw
If it's a trait method, this checks the stability attribute of the method inside the trait definition. Otherwise, it checks the method implementation itself. Close #8961.
2 parents 47c9a35 + 4f95dce commit dc65762

File tree

5 files changed

+171
-53
lines changed

5 files changed

+171
-53
lines changed

src/librustc/driver/driver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
312312
&exported_items, reachable_map, crate));
313313

314314
time(time_passes, "lint checking", (), |_|
315-
lint::check_crate(ty_cx, &exported_items, crate));
315+
lint::check_crate(ty_cx, method_map, &exported_items, crate));
316316

317317
CrateAnalysis {
318318
exp_map2: exp_map2,

src/librustc/metadata/encoder.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,10 @@ fn encode_info_for_method(ecx: &EncodeContext,
812812
encode_bounds_and_type(ebml_w, ecx, &tpt);
813813

814814
encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident));
815+
match ast_method_opt {
816+
Some(ast_method) => encode_attributes(ebml_w, ast_method.attrs),
817+
None => ()
818+
}
815819

816820
for ast_method in ast_method_opt.iter() {
817821
let num_params = tpt.generics.type_param_defs.len();
@@ -1205,11 +1209,13 @@ fn encode_info_for_item(ecx: &EncodeContext,
12051209
}
12061210

12071211
match ms[i] {
1208-
required(_) => {
1212+
required(ref tm) => {
1213+
encode_attributes(ebml_w, tm.attrs);
12091214
encode_method_sort(ebml_w, 'r');
12101215
}
12111216

12121217
provided(m) => {
1218+
encode_attributes(ebml_w, m.attrs);
12131219
// If this is a static method, we've already encoded
12141220
// this.
12151221
if method_ty.explicit_self != sty_static {

src/librustc/middle/lint.rs

+38-8
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use driver::session;
3737
use middle::privacy;
3838
use middle::trans::adt; // for `adt::is_ffi_safe`
3939
use middle::ty;
40+
use middle::typeck;
4041
use middle::pat_util;
4142
use metadata::csearch;
4243
use util::ppaux::{ty_to_str};
@@ -359,6 +360,9 @@ struct Context<'a> {
359360
cur: SmallIntMap<(level, LintSource)>,
360361
// context we're checking in (used to access fields like sess)
361362
tcx: ty::ctxt,
363+
// maps from an expression id that corresponds to a method call to the
364+
// details of the method to be invoked
365+
method_map: typeck::method_map,
362366
// Items exported by the crate; used by the missing_doc lint.
363367
exported_items: &'a privacy::ExportedItems,
364368
// The id of the current `ast::struct_def` being walked.
@@ -1176,20 +1180,43 @@ fn check_missing_doc_variant(cx: &Context, v: &ast::variant) {
11761180
/// Checks for use of items with #[deprecated], #[experimental] and
11771181
/// #[unstable] (or none of them) attributes.
11781182
fn check_stability(cx: &Context, e: &ast::Expr) {
1179-
let def = match e.node {
1180-
ast::ExprMethodCall(..) |
1181-
ast::ExprPath(..) |
1182-
ast::ExprStruct(..) => {
1183+
let id = match e.node {
1184+
ast::ExprPath(..) | ast::ExprStruct(..) => {
11831185
match cx.tcx.def_map.find(&e.id) {
1184-
Some(&def) => def,
1186+
Some(&def) => ast_util::def_id_of_def(def),
1187+
None => return
1188+
}
1189+
}
1190+
ast::ExprMethodCall(..) => {
1191+
match cx.method_map.find(&e.id) {
1192+
Some(&typeck::method_map_entry { origin, .. }) => {
1193+
match origin {
1194+
typeck::method_static(def_id) => {
1195+
// If this implements a trait method, get def_id
1196+
// of the method inside trait definition.
1197+
// Otherwise, use the current def_id (which refers
1198+
// to the method inside impl).
1199+
ty::trait_method_of_method(
1200+
cx.tcx, def_id).unwrap_or(def_id)
1201+
}
1202+
typeck::method_param(typeck::method_param {
1203+
trait_id: trait_id,
1204+
method_num: index,
1205+
..
1206+
})
1207+
| typeck::method_object(typeck::method_object {
1208+
trait_id: trait_id,
1209+
method_num: index,
1210+
..
1211+
}) => ty::trait_method(cx.tcx, trait_id, index).def_id
1212+
}
1213+
}
11851214
None => return
11861215
}
11871216
}
11881217
_ => return
11891218
};
11901219

1191-
let id = ast_util::def_id_of_def(def);
1192-
11931220
let stability = if ast_util::is_local(id) {
11941221
// this crate
11951222
match cx.tcx.items.find(&id.node) {
@@ -1208,7 +1235,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
12081235
None => return
12091236
}
12101237
}
1211-
_ => cx.tcx.sess.bug(format!("handle_def: {:?} not found", id))
1238+
_ => cx.tcx.sess.span_bug(e.span,
1239+
format!("handle_def: {:?} not found", id))
12121240
}
12131241
} else {
12141242
// cross-crate
@@ -1395,12 +1423,14 @@ impl<'a> IdVisitingOperation for Context<'a> {
13951423
}
13961424

13971425
pub fn check_crate(tcx: ty::ctxt,
1426+
method_map: typeck::method_map,
13981427
exported_items: &privacy::ExportedItems,
13991428
crate: &ast::Crate) {
14001429
let mut cx = Context {
14011430
dict: @get_lint_dict(),
14021431
cur: SmallIntMap::new(),
14031432
tcx: tcx,
1433+
method_map: method_map,
14041434
exported_items: exported_items,
14051435
cur_struct_def_id: -1,
14061436
is_doc_hidden: false,

src/librustc/middle/ty.rs

+53-15
Original file line numberDiff line numberDiff line change
@@ -4540,29 +4540,67 @@ pub fn populate_implementations_for_trait_if_necessary(
45404540
tcx.populated_external_traits.insert(trait_id);
45414541
}
45424542

4543-
/// If the given def ID describes a trait method, returns the ID of the trait
4544-
/// that the method belongs to. Otherwise, returns `None`.
4543+
/// Given the def_id of an impl, return the def_id of the trait it implements.
4544+
/// If it implements no trait, return `None`.
4545+
pub fn trait_id_of_impl(tcx: ctxt,
4546+
def_id: ast::DefId) -> Option<ast::DefId> {
4547+
let node = match tcx.items.find(&def_id.node) {
4548+
Some(node) => node,
4549+
None => return None
4550+
};
4551+
match node {
4552+
&ast_map::node_item(item, _) => {
4553+
match item.node {
4554+
ast::item_impl(_, Some(ref trait_ref), _, _) => {
4555+
Some(node_id_to_trait_ref(tcx, trait_ref.ref_id).def_id)
4556+
}
4557+
_ => None
4558+
}
4559+
}
4560+
_ => None
4561+
}
4562+
}
4563+
4564+
/// If the given def ID describes a method belonging to a trait (either a
4565+
/// default method or an implementation of a trait method), return the ID of
4566+
/// the trait that the method belongs to. Otherwise, return `None`.
45454567
pub fn trait_of_method(tcx: ctxt, def_id: ast::DefId)
45464568
-> Option<ast::DefId> {
4569+
if def_id.crate != LOCAL_CRATE {
4570+
return csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
4571+
}
45474572
match tcx.methods.find(&def_id) {
4548-
Some(method_descriptor) => {
4549-
match method_descriptor.container {
4550-
TraitContainer(id) => return Some(id),
4551-
_ => {}
4573+
Some(method) => {
4574+
match method.container {
4575+
TraitContainer(def_id) => Some(def_id),
4576+
ImplContainer(def_id) => trait_id_of_impl(tcx, def_id),
45524577
}
45534578
}
4554-
None => {}
4579+
None => None
45554580
}
4581+
}
45564582

4557-
// If the method was in the local crate, then if we got here we know the
4558-
// answer is negative.
4559-
if def_id.crate == LOCAL_CRATE {
4560-
return None
4583+
/// If the given def ID describes a method belonging to a trait, (either a
4584+
/// default method or an implementation of a trait method), return the ID of
4585+
/// the method inside trait definition (this means that if the given def ID
4586+
/// is already that of the original trait method, then the return value is
4587+
/// the same).
4588+
/// Otherwise, return `None`.
4589+
pub fn trait_method_of_method(tcx: ctxt,
4590+
def_id: ast::DefId) -> Option<ast::DefId> {
4591+
let name = match tcx.methods.find(&def_id) {
4592+
Some(method) => method.ident.name,
4593+
None => return None
4594+
};
4595+
match trait_of_method(tcx, def_id) {
4596+
Some(trait_did) => {
4597+
let trait_methods = ty::trait_methods(tcx, trait_did);
4598+
trait_methods.iter()
4599+
.position(|m| m.ident.name == name)
4600+
.map(|idx| ty::trait_method(tcx, trait_did, idx).def_id)
4601+
}
4602+
None => None
45614603
}
4562-
4563-
let result = csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
4564-
4565-
result
45664604
}
45674605

45684606
/// Creates a hash of the type `t` which will be the same no matter what crate

src/test/compile-fail/lint-stability.rs

+72-28
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,32 @@ mod cross_crate {
2626
let foo = MethodTester;
2727

2828
deprecated(); //~ ERROR use of deprecated item
29-
foo.method_deprecated(); // ~ ERROR use of deprecated item
30-
foo.trait_deprecated(); // ~ ERROR use of deprecated item
29+
foo.method_deprecated(); //~ ERROR use of deprecated item
30+
foo.trait_deprecated(); //~ ERROR use of deprecated item
3131

3232
deprecated_text(); //~ ERROR use of deprecated item: text
33-
foo.method_deprecated_text(); // ~ ERROR use of deprecated item: text
34-
foo.trait_deprecated_text(); // ~ ERROR use of deprecated item: text
33+
foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
34+
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
3535

3636
experimental(); //~ ERROR use of experimental item
37-
foo.method_experimental(); // ~ ERROR use of experimental item
38-
foo.trait_experimental(); // ~ ERROR use of experimental item
37+
foo.method_experimental(); //~ ERROR use of experimental item
38+
foo.trait_experimental(); //~ ERROR use of experimental item
3939

4040
experimental_text(); //~ ERROR use of experimental item: text
41-
foo.method_experimental_text(); // ~ ERROR use of experimental item: text
42-
foo.trait_experimental_text(); // ~ ERROR use of experimental item: text
41+
foo.method_experimental_text(); //~ ERROR use of experimental item: text
42+
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
4343

4444
unstable(); //~ ERROR use of unstable item
45-
foo.method_unstable(); // ~ ERROR use of unstable item
46-
foo.trait_unstable(); // ~ ERROR use of unstable item
45+
foo.method_unstable(); //~ ERROR use of unstable item
46+
foo.trait_unstable(); //~ ERROR use of unstable item
4747

4848
unstable_text(); //~ ERROR use of unstable item: text
49-
foo.method_unstable_text(); // ~ ERROR use of unstable item: text
50-
foo.trait_unstable_text(); // ~ ERROR use of unstable item: text
49+
foo.method_unstable_text(); //~ ERROR use of unstable item: text
50+
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
5151

5252
unmarked(); //~ ERROR use of unmarked item
53-
foo.method_unmarked(); // ~ ERROR use of unmarked item
54-
foo.trait_unmarked(); // ~ ERROR use of unmarked item
53+
foo.method_unmarked(); //~ ERROR use of unmarked item
54+
foo.trait_unmarked(); //~ ERROR use of unmarked item
5555

5656
stable();
5757
foo.method_stable();
@@ -102,6 +102,28 @@ mod cross_crate {
102102
let _ = FrozenVariant;
103103
let _ = LockedVariant;
104104
}
105+
106+
fn test_method_param<F: Trait>(foo: F) {
107+
foo.trait_deprecated(); //~ ERROR use of deprecated item
108+
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
109+
foo.trait_experimental(); //~ ERROR use of experimental item
110+
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
111+
foo.trait_unstable(); //~ ERROR use of unstable item
112+
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
113+
foo.trait_unmarked(); //~ ERROR use of unmarked item
114+
foo.trait_stable();
115+
}
116+
117+
fn test_method_object(foo: &Trait) {
118+
foo.trait_deprecated(); //~ ERROR use of deprecated item
119+
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
120+
foo.trait_experimental(); //~ ERROR use of experimental item
121+
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
122+
foo.trait_unstable(); //~ ERROR use of unstable item
123+
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
124+
foo.trait_unmarked(); //~ ERROR use of unmarked item
125+
foo.trait_stable();
126+
}
105127
}
106128

107129
mod this_crate {
@@ -259,32 +281,32 @@ mod this_crate {
259281
let foo = MethodTester;
260282

261283
deprecated(); //~ ERROR use of deprecated item
262-
foo.method_deprecated(); // ~ ERROR use of deprecated item
263-
foo.trait_deprecated(); // ~ ERROR use of deprecated item
284+
foo.method_deprecated(); //~ ERROR use of deprecated item
285+
foo.trait_deprecated(); //~ ERROR use of deprecated item
264286

265287
deprecated_text(); //~ ERROR use of deprecated item: text
266-
foo.method_deprecated_text(); // ~ ERROR use of deprecated item: text
267-
foo.trait_deprecated_text(); // ~ ERROR use of deprecated item: text
288+
foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
289+
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
268290

269291
experimental(); //~ ERROR use of experimental item
270-
foo.method_experimental(); // ~ ERROR use of experimental item
271-
foo.trait_experimental(); // ~ ERROR use of experimental item
292+
foo.method_experimental(); //~ ERROR use of experimental item
293+
foo.trait_experimental(); //~ ERROR use of experimental item
272294

273295
experimental_text(); //~ ERROR use of experimental item: text
274-
foo.method_experimental_text(); // ~ ERROR use of experimental item: text
275-
foo.trait_experimental_text(); // ~ ERROR use of experimental item: text
296+
foo.method_experimental_text(); //~ ERROR use of experimental item: text
297+
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
276298

277299
unstable(); //~ ERROR use of unstable item
278-
foo.method_unstable(); // ~ ERROR use of unstable item
279-
foo.trait_unstable(); // ~ ERROR use of unstable item
300+
foo.method_unstable(); //~ ERROR use of unstable item
301+
foo.trait_unstable(); //~ ERROR use of unstable item
280302

281303
unstable_text(); //~ ERROR use of unstable item: text
282-
foo.method_unstable_text(); // ~ ERROR use of unstable item: text
283-
foo.trait_unstable_text(); // ~ ERROR use of unstable item: text
304+
foo.method_unstable_text(); //~ ERROR use of unstable item: text
305+
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
284306

285307
unmarked(); //~ ERROR use of unmarked item
286-
foo.method_unmarked(); // ~ ERROR use of unmarked item
287-
foo.trait_unmarked(); // ~ ERROR use of unmarked item
308+
foo.method_unmarked(); //~ ERROR use of unmarked item
309+
foo.trait_unmarked(); //~ ERROR use of unmarked item
288310

289311
stable();
290312
foo.method_stable();
@@ -335,6 +357,28 @@ mod this_crate {
335357
let _ = FrozenVariant;
336358
let _ = LockedVariant;
337359
}
360+
361+
fn test_method_param<F: Trait>(foo: F) {
362+
foo.trait_deprecated(); //~ ERROR use of deprecated item
363+
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
364+
foo.trait_experimental(); //~ ERROR use of experimental item
365+
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
366+
foo.trait_unstable(); //~ ERROR use of unstable item
367+
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
368+
foo.trait_unmarked(); //~ ERROR use of unmarked item
369+
foo.trait_stable();
370+
}
371+
372+
fn test_method_object(foo: &Trait) {
373+
foo.trait_deprecated(); //~ ERROR use of deprecated item
374+
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
375+
foo.trait_experimental(); //~ ERROR use of experimental item
376+
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
377+
foo.trait_unstable(); //~ ERROR use of unstable item
378+
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
379+
foo.trait_unmarked(); //~ ERROR use of unmarked item
380+
foo.trait_stable();
381+
}
338382
}
339383

340384
fn main() {}

0 commit comments

Comments
 (0)