about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs162
-rw-r--r--src/test/incremental/hashes/function_interfaces.rs400
2 files changed, 546 insertions, 16 deletions
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 393f99b3eb8..3df68ac583d 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -15,6 +15,11 @@
 
 use self::SawExprComponent::*;
 use self::SawAbiComponent::*;
+use self::SawItemComponent::*;
+use self::SawPatComponent::*;
+use self::SawTyComponent::*;
+use self::SawTraitOrImplItemComponent::*;
+use syntax::abi::Abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::parse::token;
 use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
@@ -155,11 +160,11 @@ enum SawAbiComponent<'a> {
 
     SawMod,
     SawForeignItem,
-    SawItem,
-    SawTy,
+    SawItem(SawItemComponent),
+    SawTy(SawTyComponent),
     SawGenerics,
-    SawTraitItem,
-    SawImplItem,
+    SawTraitItem(SawTraitOrImplItemComponent),
+    SawImplItem(SawTraitOrImplItemComponent),
     SawStructField,
     SawVariant,
     SawPath(bool),
@@ -167,7 +172,7 @@ enum SawAbiComponent<'a> {
     SawPathParameters,
     SawPathListItem,
     SawBlock,
-    SawPat,
+    SawPat(SawPatComponent),
     SawLocal,
     SawArm,
     SawExpr(SawExprComponent<'a>),
@@ -198,6 +203,9 @@ enum SawAbiComponent<'a> {
 /// because the SVH is just a developer convenience; there is no
 /// guarantee of collision-freedom, hash collisions are just
 /// (hopefully) unlikely.)
+///
+/// The xxxComponent enums and saw_xxx functions for Item, Pat,
+/// Ty, TraitItem and ImplItem follow the same methodology.
 #[derive(Hash)]
 enum SawExprComponent<'a> {
 
@@ -267,6 +275,134 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
     }
 }
 
+#[derive(Hash)]
+enum SawItemComponent {
+    SawItemExternCrate,
+    SawItemUse,
+    SawItemStatic(Mutability),
+    SawItemConst,
+    SawItemFn(Unsafety, Constness, Abi),
+    SawItemMod,
+    SawItemForeignMod,
+    SawItemTy,
+    SawItemEnum,
+    SawItemStruct,
+    SawItemUnion,
+    SawItemTrait(Unsafety),
+    SawItemDefaultImpl(Unsafety),
+    SawItemImpl(Unsafety, ImplPolarity)
+}
+
+fn saw_item(node: &Item_) -> SawItemComponent {
+    match *node {
+        ItemExternCrate(..) => SawItemExternCrate,
+        ItemUse(..) => SawItemUse,
+        ItemStatic(_, mutability, _) => SawItemStatic(mutability),
+        ItemConst(..) =>SawItemConst,
+        ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
+        ItemMod(..) => SawItemMod,
+        ItemForeignMod(..) => SawItemForeignMod,
+        ItemTy(..) => SawItemTy,
+        ItemEnum(..) => SawItemEnum,
+        ItemStruct(..) => SawItemStruct,
+        ItemUnion(..) => SawItemUnion,
+        ItemTrait(unsafety, ..) => SawItemTrait(unsafety),
+        ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety),
+        ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity)
+    }
+}
+
+#[derive(Hash)]
+enum SawPatComponent {
+    SawPatWild,
+    SawPatBinding(BindingMode),
+    SawPatStruct,
+    SawPatTupleStruct,
+    SawPatPath,
+    SawPatTuple,
+    SawPatBox,
+    SawPatRef(Mutability),
+    SawPatLit,
+    SawPatRange,
+    SawPatSlice
+}
+
+fn saw_pat(node: &PatKind) -> SawPatComponent {
+    match *node {
+        PatKind::Wild => SawPatWild,
+        PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode),
+        PatKind::Struct(..) => SawPatStruct,
+        PatKind::TupleStruct(..) => SawPatTupleStruct,
+        PatKind::Path(..) => SawPatPath,
+        PatKind::Tuple(..) => SawPatTuple,
+        PatKind::Box(..) => SawPatBox,
+        PatKind::Ref(_, mutability) => SawPatRef(mutability),
+        PatKind::Lit(..) => SawPatLit,
+        PatKind::Range(..) => SawPatRange,
+        PatKind::Slice(..) => SawPatSlice
+    }
+}
+
+#[derive(Hash)]
+enum SawTyComponent {
+    SawTySlice,
+    SawTyArray,
+    SawTyPtr(Mutability),
+    SawTyRptr(Mutability),
+    SawTyBareFn(Unsafety, Abi),
+    SawTyNever,
+    SawTyTup,
+    SawTyPath,
+    SawTyObjectSum,
+    SawTyPolyTraitRef,
+    SawTyImplTrait,
+    SawTyTypeof,
+    SawTyInfer
+}
+
+fn saw_ty(node: &Ty_) -> SawTyComponent {
+    match *node {
+      TySlice(..) => SawTySlice,
+      TyArray(..) => SawTyArray,
+      TyPtr(ref mty) => SawTyPtr(mty.mutbl),
+      TyRptr(_, ref mty) => SawTyRptr(mty.mutbl),
+      TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi),
+      TyNever => SawTyNever,
+      TyTup(..) => SawTyTup,
+      TyPath(..) => SawTyPath,
+      TyObjectSum(..) => SawTyObjectSum,
+      TyPolyTraitRef(..) => SawTyPolyTraitRef,
+      TyImplTrait(..) => SawTyImplTrait,
+      TyTypeof(..) => SawTyTypeof,
+      TyInfer => SawTyInfer
+    }
+}
+
+#[derive(Hash)]
+enum SawTraitOrImplItemComponent {
+    SawTraitOrImplItemConst,
+    SawTraitOrImplItemMethod(Unsafety, Constness, Abi),
+    SawTraitOrImplItemType
+}
+
+fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
+    match *ti {
+        ConstTraitItem(..) => SawTraitOrImplItemConst,
+        MethodTraitItem(ref sig, _) =>
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
+        TypeTraitItem(..) => SawTraitOrImplItemType
+    }
+}
+
+fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
+    match *ii {
+        ImplItemKind::Const(..) => SawTraitOrImplItemConst,
+        ImplItemKind::Method(ref sig, _) =>
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
+        ImplItemKind::Type(..) => SawTraitOrImplItemType
+    }
+}
+
 #[derive(Clone, Copy, Hash, Eq, PartialEq)]
 enum SawSpanExpnKind {
     NoExpansion,
@@ -383,10 +519,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_item(&mut self, i: &'tcx Item) {
         debug!("visit_item: {:?} st={:?}", i, self.st);
-
-        SawItem.hash(self.st);
-        // Hash the value of the discriminant of the Item variant.
-        self.hash_discriminant(&i.node);
+        SawItem(saw_item(&i.node)).hash(self.st);
         hash_span!(self, i.span);
         hash_attrs!(self, &i.attrs);
         visit::walk_item(self, i)
@@ -399,7 +532,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_ty(&mut self, t: &'tcx Ty) {
         debug!("visit_ty: st={:?}", self.st);
-        SawTy.hash(self.st);
+        SawTy(saw_ty(&t.node)).hash(self.st);
         hash_span!(self, t.span);
         visit::walk_ty(self, t)
     }
@@ -412,8 +545,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
         debug!("visit_trait_item: st={:?}", self.st);
-        SawTraitItem.hash(self.st);
-        self.hash_discriminant(&ti.node);
+        SawTraitItem(saw_trait_item(&ti.node)).hash(self.st);
         hash_span!(self, ti.span);
         hash_attrs!(self, &ti.attrs);
         visit::walk_trait_item(self, ti)
@@ -421,8 +553,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
         debug!("visit_impl_item: st={:?}", self.st);
-        SawImplItem.hash(self.st);
-        self.hash_discriminant(&ii.node);
+        SawImplItem(saw_impl_item(&ii.node)).hash(self.st);
         hash_span!(self, ii.span);
         hash_attrs!(self, &ii.attrs);
         visit::walk_impl_item(self, ii)
@@ -452,8 +583,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_pat(&mut self, p: &'tcx Pat) {
         debug!("visit_pat: st={:?}", self.st);
-        SawPat.hash(self.st);
-        self.hash_discriminant(&p.node);
+        SawPat(saw_pat(&p.node)).hash(self.st);
         hash_span!(self, p.span);
         visit::walk_pat(self, p)
     }
diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs
new file mode 100644
index 00000000000..93d94cd1a19
--- /dev/null
+++ b/src/test/incremental/hashes/function_interfaces.rs
@@ -0,0 +1,400 @@
+// 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 function interfaces.
+
+// 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(conservative_impl_trait)]
+#![feature(intrinsics)]
+#![feature(linkage)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+// Add Parameter ---------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn add_parameter() {}
+
+#[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")]
+fn add_parameter(p: i32) {}
+
+
+// Add Return Type -------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn add_return_type() {}
+
+#[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")]
+fn add_return_type() -> () {}
+
+
+// Change Parameter Type -------------------------------------------------------
+
+#[cfg(cfail1)]
+fn type_of_parameter(p: i32) {}
+
+#[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")]
+fn type_of_parameter(p: i64) {}
+
+
+// Change Parameter Type Reference ---------------------------------------------
+
+#[cfg(cfail1)]
+fn type_of_parameter_ref(p: &i32) {}
+
+#[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")]
+fn type_of_parameter_ref(p: &mut i32) {}
+
+
+// Change Parameter Order ------------------------------------------------------
+
+#[cfg(cfail1)]
+fn order_of_parameters(p1: i32, p2: i64) {}
+
+#[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")]
+fn order_of_parameters(p2: i64, p1: i32) {}
+
+
+// Unsafe ----------------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn make_unsafe() {}
+
+#[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")]
+unsafe fn make_unsafe() {}
+
+
+// Extern ----------------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn make_extern() {}
+
+#[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")]
+extern fn make_extern() {}
+
+
+// Extern C Extern Rust-Intrinsic ----------------------------------------------
+
+#[cfg(cfail1)]
+extern "C" fn make_intrinsic() {}
+
+#[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")]
+extern "rust-intrinsic" fn make_intrinsic() {}
+
+
+// Type Parameter --------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn type_parameter() {}
+
+#[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")]
+fn type_parameter<T>() {}
+
+
+// Lifetime Parameter ----------------------------------------------------------
+
+#[cfg(cfail1)]
+fn lifetime_parameter() {}
+
+#[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")]
+fn lifetime_parameter<'a>() {}
+
+
+// Trait Bound -----------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn trait_bound<T>() {}
+
+#[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")]
+fn trait_bound<T: Eq>() {}
+
+
+// Builtin Bound ---------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn builtin_bound<T>() {}
+
+#[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")]
+fn builtin_bound<T: Send>() {}
+
+
+// Lifetime Bound --------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn lifetime_bound<'a, T>() {}
+
+#[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")]
+fn lifetime_bound<'a, T: 'a>() {}
+
+
+// Second Trait Bound ----------------------------------------------------------
+
+#[cfg(cfail1)]
+fn second_trait_bound<T: Eq>() {}
+
+#[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")]
+fn second_trait_bound<T: Eq + Clone>() {}
+
+
+// Second Builtin Bound --------------------------------------------------------
+
+#[cfg(cfail1)]
+fn second_builtin_bound<T: Send>() {}
+
+#[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")]
+fn second_builtin_bound<T: Send + Sized>() {}
+
+
+// Second Lifetime Bound -------------------------------------------------------
+
+#[cfg(cfail1)]
+fn second_lifetime_bound<'a, 'b, T: 'a>() {}
+
+#[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")]
+fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {}
+
+
+// Inline ----------------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn inline() {}
+
+#[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")]
+#[inline]
+fn inline() {}
+
+
+// Inline Never ----------------------------------------------------------------
+
+#[cfg(cfail1)]
+#[inline(always)]
+fn inline_never() {}
+
+#[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")]
+#[inline(never)]
+fn inline_never() {}
+
+
+// No Mangle -------------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn no_mangle() {}
+
+#[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")]
+#[no_mangle]
+fn no_mangle() {}
+
+
+// Linkage ---------------------------------------------------------------------
+
+#[cfg(cfail1)]
+fn linkage() {}
+
+#[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")]
+#[linkage="weak_odr"]
+fn linkage() {}
+
+
+// Return Impl Trait -----------------------------------------------------------
+
+#[cfg(cfail1)]
+fn return_impl_trait() -> i32 {
+    0
+}
+
+#[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")]
+fn return_impl_trait() -> impl Clone {
+    0
+}
+
+
+// Change Return Impl Trait ----------------------------------------------------
+
+#[cfg(cfail1)]
+fn change_return_impl_trait() -> impl Clone {
+    0
+}
+
+#[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")]
+fn change_return_impl_trait() -> impl Copy {
+    0
+}
+
+
+// Change Return Type Indirectly -----------------------------------------------
+
+struct ReferencedType1;
+struct ReferencedType2;
+
+mod change_return_type_indirectly {
+    #[cfg(cfail1)]
+    use super::ReferencedType1 as ReturnType;
+    #[cfg(not(cfail1))]
+    use super::ReferencedType2 as ReturnType;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn indirect_return_type() -> ReturnType {
+        ReturnType {}
+    }
+}
+
+
+// Change Parameter Type Indirectly --------------------------------------------
+
+mod change_parameter_type_indirectly {
+    #[cfg(cfail1)]
+    use super::ReferencedType1 as ParameterType;
+    #[cfg(not(cfail1))]
+    use super::ReferencedType2 as ParameterType;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn indirect_parameter_type(p: ParameterType) {}
+}
+
+
+// Change Trait Bound Indirectly -----------------------------------------------
+
+trait ReferencedTrait1 {}
+trait ReferencedTrait2 {}
+
+mod change_trait_bound_indirectly {
+    #[cfg(cfail1)]
+    use super::ReferencedTrait1 as Trait;
+    #[cfg(not(cfail1))]
+    use super::ReferencedTrait2 as Trait;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn indirect_trait_bound<T: Trait>(p: T) {}
+}
+
+
+// Change Trait Bound Indirectly In Where Clause -------------------------------
+
+mod change_trait_bound_indirectly_in_where_clause {
+    #[cfg(cfail1)]
+    use super::ReferencedTrait1 as Trait;
+    #[cfg(not(cfail1))]
+    use super::ReferencedTrait2 as Trait;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn indirect_trait_bound_where<T>(p: T) where T: Trait {}
+}