about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs25
-rw-r--r--library/std/src/collections/hash/map.rs5
-rw-r--r--tests/ui/wf/wf-associated-const.rs42
-rw-r--r--tests/ui/wf/wf-associated-const.stderr14
-rw-r--r--tests/ui/wf/wf-static-method.rs13
-rw-r--r--tests/ui/wf/wf-static-method.stderr47
6 files changed, 89 insertions, 57 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 4a76d877af0..011b5b760c2 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
+use rustc_hir::def::DefKind;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -195,7 +196,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     pub(crate) fn create(mut self) -> CreateResult<'tcx> {
-        let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
+        let tcx = self.infcx.tcx;
+        let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
+        let span = tcx.def_span(defining_ty_def_id);
 
         // Insert the facts we know from the predicates. Why? Why not.
         let param_env = self.param_env;
@@ -275,6 +278,26 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             normalized_inputs_and_output.push(norm_ty);
         }
 
+        // Add implied bounds from impl header.
+        if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
+            for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
+                let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = self
+                    .param_env
+                    .and(type_op::normalize::Normalize::new(ty))
+                    .fully_perform(self.infcx, span)
+                else {
+                    tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
+                    continue;
+                };
+                constraints.extend(c);
+
+                // We currently add implied bounds from the normalized ty only.
+                // This is more conservative and matches wfcheck behavior.
+                let c = self.add_implied_bounds(norm_ty);
+                constraints.extend(c);
+            }
+        }
+
         for c in constraints {
             self.push_region_constraints(c, span);
         }
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 1a416a4d10b..39e94902cfe 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -3049,9 +3049,8 @@ where
 #[stable(feature = "hash_extend_copy", since = "1.4.0")]
 impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
 where
-    // FIXME(aliemjay): the bound `+ 'a` should not be necessary.
-    K: Eq + Hash + Copy + 'a,
-    V: Copy + 'a,
+    K: Eq + Hash + Copy,
+    V: Copy,
     S: BuildHasher,
 {
     #[inline]
diff --git a/tests/ui/wf/wf-associated-const.rs b/tests/ui/wf/wf-associated-const.rs
new file mode 100644
index 00000000000..dffa1713eff
--- /dev/null
+++ b/tests/ui/wf/wf-associated-const.rs
@@ -0,0 +1,42 @@
+// check that associated consts can assume the impl header is well-formed.
+
+// FIXME(aliemjay): we should check the impl header is WF at the use site
+// but we currently don't in some cases. This is *unsound*.
+
+trait Foo<'a, 'b, T>: Sized {
+    const EVIL: fn(u: &'b u32) -> &'a u32;
+}
+
+struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>);
+
+impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
+    const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
+}
+
+struct IndirectEvil<'a, 'b: 'a>(Option<&'a &'b ()>);
+
+impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
+    const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
+}
+
+impl<'a, 'b> Evil<'a, 'b> {
+    const INHERENT_EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
+}
+
+// while static methods can *assume* this, we should still
+// *check* that it holds at the use site.
+
+fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+    <()>::EVIL(b) // FIXME: should be an error
+}
+
+fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+    <IndirectEvil>::EVIL(b) // FIXME: should be an error
+}
+
+fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+    <Evil>::INHERENT_EVIL(b)
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/wf/wf-associated-const.stderr b/tests/ui/wf/wf-associated-const.stderr
new file mode 100644
index 00000000000..e025d5d468a
--- /dev/null
+++ b/tests/ui/wf/wf-associated-const.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/wf-associated-const.rs:38:5
+   |
+LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     <Evil>::INHERENT_EVIL(b)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/wf/wf-static-method.rs b/tests/ui/wf/wf-static-method.rs
index 7ff195230bf..66546ac489d 100644
--- a/tests/ui/wf/wf-static-method.rs
+++ b/tests/ui/wf/wf-static-method.rs
@@ -1,8 +1,4 @@
-// check that static methods don't get to assume their trait-ref
-// is well-formed.
-// FIXME(#27579): this is just a bug. However, our checking with
-// static inherent methods isn't quite working - need to
-// fix that before removing the check.
+// check that static methods can assume their trait-ref is well-formed.
 
 trait Foo<'a, 'b, T>: Sized {
     fn make_me() -> Self { loop {} }
@@ -15,7 +11,6 @@ impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
     fn make_me() -> Self { }
     fn static_evil(u: &'b u32) -> &'a u32 {
         u
-        //~^ ERROR lifetime may not live long enough
     }
 }
 
@@ -25,7 +20,6 @@ impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
     fn make_me() -> Self { IndirectEvil(None) }
     fn static_evil(u: &'b u32) -> &'a u32 {
         let me = Self::make_me();
-        //~^ ERROR lifetime may not live long enough
         loop {} // (`me` could be used for the lifetime transmute).
     }
 }
@@ -33,12 +27,11 @@ impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
 impl<'a, 'b> Evil<'a, 'b> {
     fn inherent_evil(u: &'b u32) -> &'a u32 {
         u
-        //~^ ERROR lifetime may not live long enough
     }
 }
 
-// while static methods don't get to *assume* this, we still
-// *check* that they hold.
+// while static methods can *assume* this, we should still
+// *check* that it holds at the use site.
 
 fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
     <()>::static_evil(b)
diff --git a/tests/ui/wf/wf-static-method.stderr b/tests/ui/wf/wf-static-method.stderr
index 161609a5f86..6c49098aad3 100644
--- a/tests/ui/wf/wf-static-method.stderr
+++ b/tests/ui/wf/wf-static-method.stderr
@@ -1,44 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/wf-static-method.rs:17:9
-   |
-LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
-   |      --  -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-...
-LL |         u
-   |         ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
-   |
-   = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
-  --> $DIR/wf-static-method.rs:27:18
-   |
-LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
-   |      --  -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-...
-LL |         let me = Self::make_me();
-   |                  ^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
-   |
-   = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
-  --> $DIR/wf-static-method.rs:35:9
-   |
-LL | impl<'a, 'b> Evil<'a, 'b> {
-   |      --  -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-LL |     fn inherent_evil(u: &'b u32) -> &'a u32 {
-LL |         u
-   |         ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
-   |
-   = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
-  --> $DIR/wf-static-method.rs:44:5
+  --> $DIR/wf-static-method.rs:37:5
    |
 LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |         --  -- lifetime `'b` defined here
@@ -50,7 +11,7 @@ LL |     <()>::static_evil(b)
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/wf-static-method.rs:49:5
+  --> $DIR/wf-static-method.rs:42:5
    |
 LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |                  --  -- lifetime `'b` defined here
@@ -62,7 +23,7 @@ LL |     <IndirectEvil>::static_evil(b)
    = help: consider adding the following bound: `'b: 'a`
 
 error: lifetime may not live long enough
-  --> $DIR/wf-static-method.rs:54:5
+  --> $DIR/wf-static-method.rs:47:5
    |
 LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |                  --  -- lifetime `'b` defined here
@@ -73,5 +34,5 @@ LL |     <Evil>::inherent_evil(b)
    |
    = help: consider adding the following bound: `'b: 'a`
 
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors