about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_passes/messages.ftl3
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs21
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs7
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs52
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs72
-rw-r--r--tests/ui/traits/negative-bounds/associated-constraints.rs4
-rw-r--r--tests/ui/traits/negative-bounds/associated-constraints.stderr20
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs23
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr69
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs9
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr21
-rw-r--r--tests/ui/traits/negative-bounds/simple.rs1
-rw-r--r--tests/ui/traits/negative-bounds/simple.stderr26
-rw-r--r--tests/ui/traits/negative-bounds/supertrait.rs1
-rw-r--r--tests/ui/traits/negative-bounds/supertrait.stderr10
16 files changed, 251 insertions, 90 deletions
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index feea02c679c..a10797626f1 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -188,6 +188,9 @@ ast_passes_module_nonascii = trying to load file for module `{$name}` with non-a
 ast_passes_negative_bound_not_supported =
     negative bounds are not supported
 
+ast_passes_negative_bound_with_parenthetical_notation =
+    parenthetical notation may not be used for negative bounds
+
 ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
     .outer = outer `impl Trait`
     .inner = nested `impl Trait` here
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index b69d4cccaf0..7f78f687055 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1312,13 +1312,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if let GenericBound::Trait(trait_ref, modifiers) = bound
             && let BoundPolarity::Negative(_) = modifiers.polarity
             && let Some(segment) = trait_ref.trait_ref.path.segments.last()
-            && let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
         {
-            for arg in &args.args {
-                if let ast::AngleBracketedArg::Constraint(constraint) = arg {
-                    self.dcx()
-                        .emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
+            match segment.args.as_deref() {
+                Some(ast::GenericArgs::AngleBracketed(args)) => {
+                    for arg in &args.args {
+                        if let ast::AngleBracketedArg::Constraint(constraint) = arg {
+                            self.dcx().emit_err(errors::ConstraintOnNegativeBound {
+                                span: constraint.span,
+                            });
+                        }
+                    }
+                }
+                // The lowered form of parenthesized generic args contains a type binding.
+                Some(ast::GenericArgs::Parenthesized(args)) => {
+                    self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation {
+                        span: args.span,
+                    });
                 }
+                None => {}
             }
         }
 
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ce5a737ef63..fcf19ce52ec 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -764,6 +764,13 @@ pub struct ConstraintOnNegativeBound {
 }
 
 #[derive(Diagnostic)]
+#[diag(ast_passes_negative_bound_with_parenthetical_notation)]
+pub struct NegativeBoundWithParentheticalNotation {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(ast_passes_invalid_unnamed_field_ty)]
 pub struct InvalidUnnamedFieldTy {
     #[primary_span]
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e6faad74384..59ea828440f 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -210,7 +210,7 @@ declare_features! (
     /// Allows the `multiple_supertrait_upcastable` lint.
     (unstable, multiple_supertrait_upcastable, "1.69.0", None),
     /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
-    (incomplete, negative_bounds, "1.71.0", None),
+    (internal, negative_bounds, "1.71.0", None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
     (internal, omit_gdb_pretty_printer_section, "1.5.0", None),
     /// Allows using `#[prelude_import]` on glob `use` items.
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 91b3807d744..d403f1a850d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -26,23 +26,36 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         span: Span,
     ) {
         let tcx = self.tcx();
+        let sized_def_id = tcx.lang_items().sized_trait();
+        let mut seen_negative_sized_bound = false;
 
         // Try to find an unbound in bounds.
         let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
         let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
             for ab in ast_bounds {
-                if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
-                    unbounds.push(ptr)
+                let hir::GenericBound::Trait(ptr, modifier) = ab else {
+                    continue;
+                };
+                match modifier {
+                    hir::TraitBoundModifier::Maybe => unbounds.push(ptr),
+                    hir::TraitBoundModifier::Negative => {
+                        if let Some(sized_def_id) = sized_def_id
+                            && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
+                        {
+                            seen_negative_sized_bound = true;
+                        }
+                    }
+                    _ => {}
                 }
             }
         };
         search_bounds(ast_bounds);
         if let Some((self_ty, where_clause)) = self_ty_where_predicates {
             for clause in where_clause {
-                if let hir::WherePredicate::BoundPredicate(pred) = clause {
-                    if pred.is_param_bound(self_ty.to_def_id()) {
-                        search_bounds(pred.bounds);
-                    }
+                if let hir::WherePredicate::BoundPredicate(pred) = clause
+                    && pred.is_param_bound(self_ty.to_def_id())
+                {
+                    search_bounds(pred.bounds);
                 }
             }
         }
@@ -53,15 +66,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             });
         }
 
-        let sized_def_id = tcx.lang_items().sized_trait();
-
         let mut seen_sized_unbound = false;
         for unbound in unbounds {
-            if let Some(sized_def_id) = sized_def_id {
-                if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) {
-                    seen_sized_unbound = true;
-                    continue;
-                }
+            if let Some(sized_def_id) = sized_def_id
+                && unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
+            {
+                seen_sized_unbound = true;
+                continue;
             }
             // There was a `?Trait` bound, but it was not `?Sized`; warn.
             tcx.dcx().span_warn(
@@ -71,15 +82,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             );
         }
 
-        // If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available.
-        if sized_def_id.is_none() {
-            // No lang item for `Sized`, so we can't add it as a bound.
-            return;
-        }
-        if seen_sized_unbound {
-            // There was in fact a `?Sized` bound, return without doing anything
-        } else {
-            // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+        if seen_sized_unbound || seen_negative_sized_bound {
+            // There was in fact a `?Sized` or `!Sized` bound;
+            // we don't need to do anything.
+        } else if sized_def_id.is_some() {
+            // There was no `?Sized` or `!Sized` bound;
+            // add `Sized` if it's available.
             bounds.push_sized(tcx, self_ty, span);
         }
     }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ebbd02e01bf..dadd4de2bf9 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -912,7 +912,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
         let mut traits = FxIndexMap::default();
         let mut fn_traits = FxIndexMap::default();
-        let mut is_sized = false;
+        let mut has_sized_bound = false;
+        let mut has_negative_sized_bound = false;
         let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
 
         for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) {
@@ -922,13 +923,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 ty::ClauseKind::Trait(pred) => {
                     let trait_ref = bound_predicate.rebind(pred.trait_ref);
 
-                    // Don't print + Sized, but rather + ?Sized if absent.
+                    // Don't print `+ Sized`, but rather `+ ?Sized` if absent.
                     if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
-                        is_sized = true;
-                        continue;
+                        match pred.polarity {
+                            ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {
+                                has_sized_bound = true;
+                                continue;
+                            }
+                            ty::ImplPolarity::Negative => has_negative_sized_bound = true,
+                        }
                     }
 
-                    self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
+                    self.insert_trait_and_projection(
+                        trait_ref,
+                        pred.polarity,
+                        None,
+                        &mut traits,
+                        &mut fn_traits,
+                    );
                 }
                 ty::ClauseKind::Projection(pred) => {
                     let proj_ref = bound_predicate.rebind(pred);
@@ -939,6 +951,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
                     self.insert_trait_and_projection(
                         trait_ref,
+                        ty::ImplPolarity::Positive,
                         Some(proj_ty),
                         &mut traits,
                         &mut fn_traits,
@@ -955,7 +968,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
         let mut first = true;
         // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
-        let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
+        let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound;
 
         for (fn_once_trait_ref, entry) in fn_traits {
             write!(self, "{}", if first { "" } else { " + " })?;
@@ -1002,18 +1015,21 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
                     _ => {
                         if entry.has_fn_once {
-                            traits.entry(fn_once_trait_ref).or_default().extend(
-                                // Group the return ty with its def id, if we had one.
-                                entry
-                                    .return_ty
-                                    .map(|ty| (tcx.require_lang_item(LangItem::FnOnce, None), ty)),
-                            );
+                            traits
+                                .entry((fn_once_trait_ref, ty::ImplPolarity::Positive))
+                                .or_default()
+                                .extend(
+                                    // Group the return ty with its def id, if we had one.
+                                    entry.return_ty.map(|ty| {
+                                        (tcx.require_lang_item(LangItem::FnOnce, None), ty)
+                                    }),
+                                );
                         }
                         if let Some(trait_ref) = entry.fn_mut_trait_ref {
-                            traits.entry(trait_ref).or_default();
+                            traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
                         }
                         if let Some(trait_ref) = entry.fn_trait_ref {
-                            traits.entry(trait_ref).or_default();
+                            traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
                         }
                     }
                 }
@@ -1023,11 +1039,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         }
 
         // Print the rest of the trait types (that aren't Fn* family of traits)
-        for (trait_ref, assoc_items) in traits {
+        for ((trait_ref, polarity), assoc_items) in traits {
             write!(self, "{}", if first { "" } else { " + " })?;
 
             self.wrap_binder(&trait_ref, |trait_ref, cx| {
                 define_scoped_cx!(cx);
+
+                if polarity == ty::ImplPolarity::Negative {
+                    p!("!");
+                }
                 p!(print(trait_ref.print_only_trait_name()));
 
                 let generics = tcx.generics_of(trait_ref.def_id);
@@ -1094,9 +1114,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             })?;
         }
 
-        if !is_sized {
-            write!(self, "{}?Sized", if first { "" } else { " + " })?;
-        } else if first {
+        let add_sized = has_sized_bound && (first || has_negative_sized_bound);
+        let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound;
+        if add_sized || add_maybe_sized {
+            if !first {
+                write!(self, " + ")?;
+            }
+            if add_maybe_sized {
+                write!(self, "?")?;
+            }
             write!(self, "Sized")?;
         }
 
@@ -1128,9 +1154,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
     fn insert_trait_and_projection(
         &mut self,
         trait_ref: ty::PolyTraitRef<'tcx>,
+        polarity: ty::ImplPolarity,
         proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
         traits: &mut FxIndexMap<
-            ty::PolyTraitRef<'tcx>,
+            (ty::PolyTraitRef<'tcx>, ty::ImplPolarity),
             FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
         >,
         fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
@@ -1139,7 +1166,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
         // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
         // super-trait ref and record it there.
-        if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() {
+        // We skip negative Fn* bounds since they can't use parenthetical notation anyway.
+        if polarity == ty::ImplPolarity::Positive
+            && let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait()
+        {
             // If we have a FnOnce, then insert it into
             if trait_def_id == fn_once_trait {
                 let entry = fn_traits.entry(trait_ref).or_default();
@@ -1167,7 +1197,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         }
 
         // Otherwise, just group our traits and projection types.
-        traits.entry(trait_ref).or_default().extend(proj_ty);
+        traits.entry((trait_ref, polarity)).or_default().extend(proj_ty);
     }
 
     fn pretty_print_inherent_projection(
diff --git a/tests/ui/traits/negative-bounds/associated-constraints.rs b/tests/ui/traits/negative-bounds/associated-constraints.rs
index bc1a0ef1708..4a7132ccde9 100644
--- a/tests/ui/traits/negative-bounds/associated-constraints.rs
+++ b/tests/ui/traits/negative-bounds/associated-constraints.rs
@@ -1,5 +1,4 @@
 #![feature(negative_bounds, associated_type_bounds)]
-//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
 
 trait Trait {
     type Assoc;
@@ -17,4 +16,7 @@ fn test3<T: !Trait<Assoc: Send>>() {}
 fn test4<T>() where T: !Trait<Assoc: Send> {}
 //~^ ERROR associated type constraints not allowed on negative bounds
 
+fn test5<T>() where T: !Fn() -> i32 {}
+//~^ ERROR parenthetical notation may not be used for negative bounds
+
 fn main() {}
diff --git a/tests/ui/traits/negative-bounds/associated-constraints.stderr b/tests/ui/traits/negative-bounds/associated-constraints.stderr
index 335ac7e5ad9..c1a6d2ca6a2 100644
--- a/tests/ui/traits/negative-bounds/associated-constraints.stderr
+++ b/tests/ui/traits/negative-bounds/associated-constraints.stderr
@@ -1,34 +1,32 @@
 error: associated type constraints not allowed on negative bounds
-  --> $DIR/associated-constraints.rs:8:19
+  --> $DIR/associated-constraints.rs:7:19
    |
 LL | fn test<T: !Trait<Assoc = i32>>() {}
    |                   ^^^^^^^^^^^
 
 error: associated type constraints not allowed on negative bounds
-  --> $DIR/associated-constraints.rs:11:31
+  --> $DIR/associated-constraints.rs:10:31
    |
 LL | fn test2<T>() where T: !Trait<Assoc = i32> {}
    |                               ^^^^^^^^^^^
 
 error: associated type constraints not allowed on negative bounds
-  --> $DIR/associated-constraints.rs:14:20
+  --> $DIR/associated-constraints.rs:13:20
    |
 LL | fn test3<T: !Trait<Assoc: Send>>() {}
    |                    ^^^^^^^^^^^
 
 error: associated type constraints not allowed on negative bounds
-  --> $DIR/associated-constraints.rs:17:31
+  --> $DIR/associated-constraints.rs:16:31
    |
 LL | fn test4<T>() where T: !Trait<Assoc: Send> {}
    |                               ^^^^^^^^^^^
 
-warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/associated-constraints.rs:1:12
+error: parenthetical notation may not be used for negative bounds
+  --> $DIR/associated-constraints.rs:19:25
    |
-LL | #![feature(negative_bounds, associated_type_bounds)]
-   |            ^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
+LL | fn test5<T>() where T: !Fn() -> i32 {}
+   |                         ^^^^^^^^^^^
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs
new file mode 100644
index 00000000000..e1e93f79920
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs
@@ -0,0 +1,23 @@
+// compile-flags: -Znext-solver
+
+#![feature(negative_bounds, negative_impls)]
+
+trait Trait {}
+impl !Trait for () {}
+
+fn produce() -> impl !Trait {}
+fn consume(_: impl Trait) {}
+
+fn main() {
+    consume(produce()); //~ ERROR the trait bound `impl !Trait: Trait` is not satisfied
+}
+
+fn weird0() -> impl Sized + !Sized {}
+//~^ ERROR mismatched types
+//~| ERROR type mismatch resolving `() == impl !Sized + Sized`
+fn weird1() -> impl !Sized + Sized {}
+//~^ ERROR mismatched types
+//~| ERROR type mismatch resolving `() == impl !Sized + Sized`
+fn weird2() -> impl !Sized {}
+//~^ ERROR mismatched types
+//~| ERROR type mismatch resolving `() == impl !Sized`
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr
new file mode 100644
index 00000000000..62792761870
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr
@@ -0,0 +1,69 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque-type-unsatisfied-bound.rs:15:36
+   |
+LL | fn weird0() -> impl Sized + !Sized {}
+   |                ------------------- ^^ types differ
+   |                |
+   |                the expected opaque type
+   |
+   = note: expected opaque type `impl !Sized + Sized`
+                found unit type `()`
+
+error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
+  --> $DIR/opaque-type-unsatisfied-bound.rs:15:16
+   |
+LL | fn weird0() -> impl Sized + !Sized {}
+   |                ^^^^^^^^^^^^^^^^^^^ types differ
+
+error[E0308]: mismatched types
+  --> $DIR/opaque-type-unsatisfied-bound.rs:18:36
+   |
+LL | fn weird1() -> impl !Sized + Sized {}
+   |                ------------------- ^^ types differ
+   |                |
+   |                the expected opaque type
+   |
+   = note: expected opaque type `impl !Sized + Sized`
+                found unit type `()`
+
+error[E0271]: type mismatch resolving `() == impl !Sized + Sized`
+  --> $DIR/opaque-type-unsatisfied-bound.rs:18:16
+   |
+LL | fn weird1() -> impl !Sized + Sized {}
+   |                ^^^^^^^^^^^^^^^^^^^ types differ
+
+error[E0308]: mismatched types
+  --> $DIR/opaque-type-unsatisfied-bound.rs:21:28
+   |
+LL | fn weird2() -> impl !Sized {}
+   |                ----------- ^^ types differ
+   |                |
+   |                the expected opaque type
+   |
+   = note: expected opaque type `impl !Sized`
+                found unit type `()`
+
+error[E0271]: type mismatch resolving `() == impl !Sized`
+  --> $DIR/opaque-type-unsatisfied-bound.rs:21:16
+   |
+LL | fn weird2() -> impl !Sized {}
+   |                ^^^^^^^^^^^ types differ
+
+error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied
+  --> $DIR/opaque-type-unsatisfied-bound.rs:12:13
+   |
+LL |     consume(produce());
+   |     ------- ^^^^^^^^^ the trait `Trait` is not implemented for `impl !Trait`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `consume`
+  --> $DIR/opaque-type-unsatisfied-bound.rs:9:20
+   |
+LL | fn consume(_: impl Trait) {}
+   |                    ^^^^^ required by this bound in `consume`
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0271, E0277, E0308.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs
new file mode 100644
index 00000000000..72bca1a8910
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs
@@ -0,0 +1,9 @@
+// compile-flags: -Znext-solver
+
+#![feature(negative_bounds, unboxed_closures)]
+
+fn produce() -> impl !Fn<(u32,)> {}
+//~^ ERROR mismatched types
+//~| ERROR type mismatch resolving `() == impl !Fn<(u32,)>`
+
+fn main() {}
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr
new file mode 100644
index 00000000000..a4fb4b2b5c4
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:34
+   |
+LL | fn produce() -> impl !Fn<(u32,)> {}
+   |                 ---------------- ^^ types differ
+   |                 |
+   |                 the expected opaque type
+   |
+   = note: expected opaque type `impl !Fn<(u32,)>`
+                found unit type `()`
+
+error[E0271]: type mismatch resolving `() == impl !Fn<(u32,)>`
+  --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
+   |
+LL | fn produce() -> impl !Fn<(u32,)> {}
+   |                 ^^^^^^^^^^^^^^^^ types differ
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0308.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/negative-bounds/simple.rs b/tests/ui/traits/negative-bounds/simple.rs
index f6d1d5169c4..a2febf353f6 100644
--- a/tests/ui/traits/negative-bounds/simple.rs
+++ b/tests/ui/traits/negative-bounds/simple.rs
@@ -1,5 +1,4 @@
 #![feature(negative_bounds, negative_impls)]
-//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
 
 fn not_copy<T: !Copy>() {}
 
diff --git a/tests/ui/traits/negative-bounds/simple.stderr b/tests/ui/traits/negative-bounds/simple.stderr
index a3cab41a2ce..6d750739e19 100644
--- a/tests/ui/traits/negative-bounds/simple.stderr
+++ b/tests/ui/traits/negative-bounds/simple.stderr
@@ -1,44 +1,36 @@
-warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/simple.rs:1:12
-   |
-LL | #![feature(negative_bounds, negative_impls)]
-   |            ^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-
 error[E0277]: the trait bound `T: !Copy` is not satisfied
-  --> $DIR/simple.rs:11:16
+  --> $DIR/simple.rs:10:16
    |
 LL |     not_copy::<T>();
    |                ^ the trait `!Copy` is not implemented for `T`
    |
 note: required by a bound in `not_copy`
-  --> $DIR/simple.rs:4:16
+  --> $DIR/simple.rs:3:16
    |
 LL | fn not_copy<T: !Copy>() {}
    |                ^^^^^ required by this bound in `not_copy`
 
 error[E0277]: the trait bound `T: !Copy` is not satisfied
-  --> $DIR/simple.rs:16:16
+  --> $DIR/simple.rs:15:16
    |
 LL |     not_copy::<T>();
    |                ^ the trait `!Copy` is not implemented for `T`
    |
 note: required by a bound in `not_copy`
-  --> $DIR/simple.rs:4:16
+  --> $DIR/simple.rs:3:16
    |
 LL | fn not_copy<T: !Copy>() {}
    |                ^^^^^ required by this bound in `not_copy`
 
 error[E0277]: the trait bound `Copyable: !Copy` is not satisfied
-  --> $DIR/simple.rs:31:16
+  --> $DIR/simple.rs:30:16
    |
 LL |     not_copy::<Copyable>();
    |                ^^^^^^^^ the trait `!Copy` is not implemented for `Copyable`
    |
    = help: the trait `Copy` is implemented for `Copyable`
 note: required by a bound in `not_copy`
-  --> $DIR/simple.rs:4:16
+  --> $DIR/simple.rs:3:16
    |
 LL | fn not_copy<T: !Copy>() {}
    |                ^^^^^ required by this bound in `not_copy`
@@ -49,13 +41,13 @@ LL | struct Copyable;
    |
 
 error[E0277]: the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied
-  --> $DIR/simple.rs:38:16
+  --> $DIR/simple.rs:37:16
    |
 LL |     not_copy::<NotNecessarilyCopyable>();
    |                ^^^^^^^^^^^^^^^^^^^^^^ the trait `!Copy` is not implemented for `NotNecessarilyCopyable`
    |
 note: required by a bound in `not_copy`
-  --> $DIR/simple.rs:4:16
+  --> $DIR/simple.rs:3:16
    |
 LL | fn not_copy<T: !Copy>() {}
    |                ^^^^^ required by this bound in `not_copy`
@@ -65,6 +57,6 @@ LL + #[derive(Copy)]
 LL | struct NotNecessarilyCopyable;
    |
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/negative-bounds/supertrait.rs b/tests/ui/traits/negative-bounds/supertrait.rs
index df0884b8b9f..a66bc4a60a0 100644
--- a/tests/ui/traits/negative-bounds/supertrait.rs
+++ b/tests/ui/traits/negative-bounds/supertrait.rs
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(negative_bounds)]
-//~^ WARN the feature `negative_bounds` is incomplete
 
 trait A: !B {}
 trait B: !A {}
diff --git a/tests/ui/traits/negative-bounds/supertrait.stderr b/tests/ui/traits/negative-bounds/supertrait.stderr
deleted file mode 100644
index f44753b624e..00000000000
--- a/tests/ui/traits/negative-bounds/supertrait.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/supertrait.rs:3:12
-   |
-LL | #![feature(negative_bounds)]
-   |            ^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-
-warning: 1 warning emitted
-