about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs11
-rw-r--r--src/test/ui/coherence/auxiliary/trait-with-const-param.rs1
-rw-r--r--src/test/ui/coherence/const-generics-orphan-check-ok.rs28
3 files changed, 39 insertions, 1 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index fa94aa19abd..da17a9c3da6 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -746,8 +746,17 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
         result
     }
 
-    // FIXME: Constants should participate in orphan checking.
     fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // All possible values for a constant parameter already exist
+        // in the crate defining the trait, so they are always non-local.
+        //
+        // Because there's no way to have an impl where the first local
+        // generic argument is a constant, we also don't have to fail
+        // the orphan check when encountering a parameter or a generic constant.
+        //
+        // This means that we can completely ignore constants during the orphan check.
+        //
+        // See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples.
         ControlFlow::CONTINUE
     }
 }
diff --git a/src/test/ui/coherence/auxiliary/trait-with-const-param.rs b/src/test/ui/coherence/auxiliary/trait-with-const-param.rs
new file mode 100644
index 00000000000..a44eb14f8e4
--- /dev/null
+++ b/src/test/ui/coherence/auxiliary/trait-with-const-param.rs
@@ -0,0 +1 @@
+pub trait Trait<const N: usize, T> {}
diff --git a/src/test/ui/coherence/const-generics-orphan-check-ok.rs b/src/test/ui/coherence/const-generics-orphan-check-ok.rs
new file mode 100644
index 00000000000..217e8aed234
--- /dev/null
+++ b/src/test/ui/coherence/const-generics-orphan-check-ok.rs
@@ -0,0 +1,28 @@
+// check-pass
+// aux-build:trait-with-const-param.rs
+extern crate trait_with_const_param;
+use trait_with_const_param::*;
+
+// Trivial case, const param after local type.
+struct Local1;
+impl<const N: usize, T> Trait<N, T> for Local1 {}
+
+// Concrete consts behave the same as foreign types,
+// so this also trivially works.
+impl Trait<3, Local1> for i32 {}
+
+// This case isn't as trivial as we would forbid type
+// parameters here, we do allow const parameters though.
+//
+// The reason that type parameters are forbidden for
+// `impl<T> Trait<T, LocalInA> for i32 {}` is that another
+// downstream crate can add `impl<T> Trait<LocalInB, T> for i32`.
+// As these two impls would overlap we forbid any impls which
+// have a type parameter in front of a local type.
+//
+// With const parameters this issue does not exist as there are no
+// constants local to another downstream crate.
+struct Local2;
+impl<const N: usize> Trait<N, Local2> for i32 {}
+
+fn main() {}