about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-11-17 17:31:01 -0800
committerGitHub <noreply@github.com>2016-11-17 17:31:01 -0800
commit35e8924dc5d5cc248f33767ff35f7aeb797a71ec (patch)
treeaa089b5c80ee7312c3b4f367288755334073049d /src/test
parentc3565372c30257bccb127ee188a4d1f25f621db7 (diff)
parentc938007f90711d6acc8b55e15a5e3cf7cc147e91 (diff)
downloadrust-35e8924dc5d5cc248f33767ff35f7aeb797a71ec.tar.gz
rust-35e8924dc5d5cc248f33767ff35f7aeb797a71ec.zip
Auto merge of #37660 - nikomatsakis:incremental-36349, r=eddyb
Separate impl items from the parent impl

This change separates impl item bodies out of the impl itself. This gives incremental more resolution. In so doing, it refactors how the visitors work, and cleans up a bit of the collect/check logic (mostly by moving things out of collect that didn't really belong there, because they were just checking conditions).

However, this is not as effective as I expected, for a kind of frustrating reason. In particular, when invoking `foo.bar()` you still wind up with dependencies on private items. The problem is that the method resolution code scans that list for methods with the name `bar` -- and this winds up touching *all* the methods, even private ones.

I can imagine two obvious ways to fix this:

- separating fn bodies from fn sigs (#35078, currently being pursued by @flodiebold)
- a more aggressive model of incremental that @michaelwoerister has been advocating, in which we hash the intermediate results (e.g., the outputs of collect) so that we can see that the intermediate result hasn't changed, even if a particular impl item has changed.

So all in all I'm not quite sure whether to land this or not. =) It still seems like it has to be a win in some cases, but not with the test cases we have just now. I can try to gin up some test cases, but I'm not sure if they will be totally realistic. On the other hand, some of the early refactorings to the visitor trait seem worthwhile to me regardless.

cc #36349 -- well, this is basically a fix for that issue, I guess

r? @michaelwoerister

NB: Based atop of @eddyb's PR https://github.com/rust-lang/rust/pull/37402; don't land until that lands.
Diffstat (limited to 'src/test')
-rw-r--r--src/test/compile-fail/dep-graph-type-alias.rs3
-rw-r--r--src/test/compile-fail/issue-3214.rs1
-rw-r--r--src/test/incremental/change_private_impl_method/struct_point.rs11
-rw-r--r--src/test/incremental/change_private_impl_method_cc/struct_point.rs24
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs128
-rw-r--r--src/test/incremental/hashes/trait_impls.rs404
6 files changed, 549 insertions, 22 deletions
diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs
index 80cc9e71c7a..2e33f11c04b 100644
--- a/src/test/compile-fail/dep-graph-type-alias.rs
+++ b/src/test/compile-fail/dep-graph-type-alias.rs
@@ -42,8 +42,9 @@ trait Trait {
 
 struct SomeType;
 
-#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
 impl SomeType {
+    #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
     fn method(&self, _: TypeAlias) {}
 }
 
diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs
index d3b932fbc53..010cfb54c1a 100644
--- a/src/test/compile-fail/issue-3214.rs
+++ b/src/test/compile-fail/issue-3214.rs
@@ -15,7 +15,6 @@ fn foo<T>() {
 
     impl<T> Drop for foo<T> {
         //~^ ERROR wrong number of type arguments
-        //~^^ ERROR the type parameter `T` is not constrained
         fn drop(&mut self) {}
     }
 }
diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs
index 8fa34bde170..46e5a88eef9 100644
--- a/src/test/incremental/change_private_impl_method/struct_point.rs
+++ b/src/test/incremental/change_private_impl_method/struct_point.rs
@@ -20,9 +20,8 @@
 
 #![rustc_partition_translated(module="struct_point-point", cfg="rpass2")]
 
-// FIXME(#37121) -- the following two modules *should* be reused but are not
-#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
@@ -60,8 +59,7 @@ mod point {
 mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    // FIXME(#37121) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -72,8 +70,7 @@ mod fn_calls_methods_in_same_impl {
 mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    // FIXME(#37121) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
index d8e5fbadad8..bb7f7025c59 100644
--- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs
+++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
@@ -19,12 +19,13 @@
 #![feature(stmt_expr_attributes)]
 #![allow(dead_code)]
 
-// FIXME(#37333) -- the following modules *should* be reused but are not
+#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
+
+// FIXME(#37720) these two should be reused, but data gets entangled across crates
 #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
 #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")]
 
 extern crate point;
 
@@ -32,7 +33,7 @@ extern crate point;
 mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
+    // FIXME(#37720) data gets entangled across crates
     #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
@@ -44,9 +45,9 @@ mod fn_calls_methods_in_same_impl {
 mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
+    // FIXME(#37720) data gets entangled across crates
     #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
-    pub fn check() {
+    pub fn dirty() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
     }
@@ -56,8 +57,7 @@ mod fn_calls_methods_in_another_impl {
 mod fn_make_struct {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -67,8 +67,7 @@ mod fn_make_struct {
 mod fn_read_field {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -78,8 +77,7 @@ mod fn_read_field {
 mod fn_write_field {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
new file mode 100644
index 00000000000..f7a390e8745
--- /dev/null
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -0,0 +1,128 @@
+// Copyright 2016 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for let expressions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+struct Foo;
+
+// Change Method Name -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_name2() { }
+}
+
+// Change Method Body -----------------------------------------------------------
+//
+// This should affect the method itself, but not the impl.
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_body() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_body() {
+        println!("Hello, world!");
+    }
+}
+
+// Change Method Privacy -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_privacy() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_privacy() { }
+}
+
+// Change Method Selfness -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_selfness() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_selfness(&self) { }
+}
+
+// Change Method Selfmutness -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_selfmutness(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_selfmutness(&mut self) { }
+}
+
diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs
new file mode 100644
index 00000000000..500aaf52324
--- /dev/null
+++ b/src/test/incremental/hashes/trait_impls.rs
@@ -0,0 +1,404 @@
+// Copyright 2016 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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for let expressions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![feature(specialization)]
+#![crate_type="rlib"]
+
+struct Foo;
+
+// Change Method Name -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeMethodNameTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodNameTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub trait ChangeMethodNameTrait {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name2();
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodNameTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name2() { }
+}
+
+// Change Method Body -----------------------------------------------------------
+//
+// This should affect the method itself, but not the trait.
+
+pub trait ChangeMethodBodyTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodBodyTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodBodyTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name() {
+        ()
+    }
+}
+
+// Change Method Selfness -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeMethodSelfnessTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodSelfnessTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeMethodSelfnessTrait {
+    fn method_name(&self);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodSelfnessTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&self) {
+        ()
+    }
+}
+
+// Change Method Selfness -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait RemoveMethodSelfnessTrait {
+    fn method_name(&self);
+}
+
+#[cfg(cfail1)]
+impl RemoveMethodSelfnessTrait for Foo {
+    fn method_name(&self) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait RemoveMethodSelfnessTrait {
+    fn method_name();
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl RemoveMethodSelfnessTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name() {
+        ()
+    }
+}
+
+// Change Method Selfmutness -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeMethodSelfmutnessTrait {
+    fn method_name(&self);
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodSelfmutnessTrait for Foo {
+    fn method_name(&self) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeMethodSelfmutnessTrait {
+    fn method_name(&mut self);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodSelfmutnessTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&mut self) {
+        ()
+    }
+}
+
+// Change item kind -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeItemKindTrait {
+    fn name();
+}
+
+#[cfg(cfail1)]
+impl ChangeItemKindTrait for Foo {
+    fn name() { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeItemKindTrait {
+    type name;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeItemKindTrait for Foo {
+    type name = ();
+}
+
+// Remove item -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait RemoveItemTrait {
+    type TypeName;
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl RemoveItemTrait for Foo {
+    type TypeName = ();
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+pub trait RemoveItemTrait {
+    type TypeName;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl RemoveItemTrait for Foo {
+    type TypeName = ();
+}
+
+// Add item -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait AddItemTrait {
+    type TypeName;
+}
+
+#[cfg(cfail1)]
+impl AddItemTrait for Foo {
+    type TypeName = ();
+}
+
+#[cfg(not(cfail1))]
+pub trait AddItemTrait {
+    type TypeName;
+    fn method_name();
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl AddItemTrait for Foo {
+    type TypeName = ();
+    fn method_name() { }
+}
+
+// Change has-value -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeHasValueTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeHasValueTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub trait ChangeHasValueTrait {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeHasValueTrait for Foo {
+    fn method_name() { }
+}
+
+// Add default
+
+pub trait AddDefaultTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl AddDefaultTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl AddDefaultTrait for Foo {
+    default fn method_name() { }
+}
+
+// Remove default
+
+pub trait RemoveDefaultTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl RemoveDefaultTrait for Foo {
+    default fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl RemoveDefaultTrait for Foo {
+    fn method_name() { }
+}
+
+// Add arguments
+
+#[cfg(cfail1)]
+pub trait AddArgumentTrait {
+    fn method_name(&self);
+}
+
+#[cfg(cfail1)]
+impl AddArgumentTrait for Foo {
+    fn method_name(&self) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait AddArgumentTrait {
+    fn method_name(&self, x: u32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl AddArgumentTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&self, _x: u32) { }
+}
+
+// Change argument type
+
+#[cfg(cfail1)]
+pub trait ChangeArgumentTypeTrait {
+    fn method_name(&self, x: u32);
+}
+
+#[cfg(cfail1)]
+impl ChangeArgumentTypeTrait for Foo {
+    fn method_name(&self, _x: u32) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeArgumentTypeTrait {
+    fn method_name(&self, x: char);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeArgumentTypeTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&self, _x: char) { }
+}
+