about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-12-02 21:58:48 +0000
committerbors <bors@rust-lang.org>2021-12-02 21:58:48 +0000
commitff23ad3179014ba258f2b540fb39dd0f26852b7a (patch)
tree205abbf762b77c2afb3e449dc31783eed1b58c00 /src
parentacbe4443cc4c9695c0b74a7b64b60333c990a400 (diff)
parentf7afd461c7a1e9431a3ce46c23bc7ccd233faa99 (diff)
downloadrust-ff23ad3179014ba258f2b540fb39dd0f26852b7a.tar.gz
rust-ff23ad3179014ba258f2b540fb39dd0f26852b7a.zip
Auto merge of #91469 - matthiaskrgr:rollup-xom3j55, r=matthiaskrgr
Rollup of 12 pull requests

Successful merges:

 - #89954 (Fix legacy_const_generic doc arguments display)
 - #91321 (Handle placeholder regions in NLL type outlive constraints)
 - #91329 (Fix incorrect usage of `EvaluatedToOk` when evaluating `TypeOutlives`)
 - #91364 (Improve error message for incorrect field accesses through raw pointers)
 - #91387 (Clarify and tidy up explanation of E0038)
 - #91410 (Move `#![feature(const_precise_live_drops)]` checks earlier in the pipeline)
 - #91435 (Improve diagnostic for missing half of binary operator in `if` condition)
 - #91444 (disable tests in Miri that take too long)
 - #91457 (Add additional test from rust issue number 91068)
 - #91460 (Document how `last_os_error` should be used)
 - #91464 (Document file path case sensitivity)
 - #91466 (Improve the comments in `Symbol::interner`.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/clean/mod.rs35
-rw-r--r--src/librustdoc/clean/types.rs3
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff (renamed from src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff)4
-rw-r--r--src/test/mir-opt/const_prop/switch_int.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff (renamed from src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff)2
-rw-r--r--src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff (renamed from src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff)4
-rw-r--r--src/test/mir-opt/simplify_if.rs2
-rw-r--r--src/test/rustdoc/legacy-const-generic.rs16
-rw-r--r--src/test/ui/consts/drop_zst.rs17
-rw-r--r--src/test/ui/consts/drop_zst.stderr9
-rw-r--r--src/test/ui/expr/if/if-without-block.stderr6
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs22
-rw-r--r--src/test/ui/lifetimes/issue-76168-hr-outlives.rs19
-rw-r--r--src/test/ui/parser/issue-91421.rs10
-rw-r--r--src/test/ui/parser/issue-91421.stderr21
-rw-r--r--src/test/ui/traits/project-modulo-regions.rs55
-rw-r--r--src/test/ui/traits/project-modulo-regions.with_clause.stderr11
-rw-r--r--src/test/ui/traits/project-modulo-regions.without_clause.stderr11
-rw-r--r--src/test/ui/typeck/issue-91210-ptr-method.fixed15
-rw-r--r--src/test/ui/typeck/issue-91210-ptr-method.rs15
-rw-r--r--src/test/ui/typeck/issue-91210-ptr-method.stderr11
23 files changed, 286 insertions, 10 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e131089f361..9c3484b4a31 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -749,11 +749,42 @@ fn clean_fn_or_proc_macro(
                 } else {
                     hir::Constness::NotConst
                 };
+            clean_fn_decl_legacy_const_generics(&mut func, attrs);
             FunctionItem(func)
         }
     }
 }
 
+/// This is needed to make it more "readable" when documenting functions using
+/// `rustc_legacy_const_generics`. More information in
+/// <https://github.com/rust-lang/rust/issues/83167>.
+fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute]) {
+    for meta_item_list in attrs
+        .iter()
+        .filter(|a| a.has_name(sym::rustc_legacy_const_generics))
+        .filter_map(|a| a.meta_item_list())
+    {
+        for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.literal()).enumerate() {
+            match literal.kind {
+                ast::LitKind::Int(a, _) => {
+                    let gen = func.generics.params.remove(0);
+                    if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } =
+                        gen
+                    {
+                        func.decl
+                            .inputs
+                            .values
+                            .insert(a as _, Argument { name, type_: *ty, is_const: true });
+                    } else {
+                        panic!("unexpected non const in position {}", pos);
+                    }
+                }
+                _ => panic!("invalid arg index"),
+            }
+        }
+    }
+}
+
 impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
     fn clean(&self, cx: &mut DocContext<'_>) -> Function {
         let (generics, decl) = enter_impl_trait(cx, |cx| {
@@ -779,7 +810,7 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
                     if name.is_empty() {
                         name = kw::Underscore;
                     }
-                    Argument { name, type_: ty.clean(cx) }
+                    Argument { name, type_: ty.clean(cx), is_const: false }
                 })
                 .collect(),
         }
@@ -798,6 +829,7 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
                 .map(|(i, ty)| Argument {
                     name: name_from_pat(body.params[i].pat),
                     type_: ty.clean(cx),
+                    is_const: false,
                 })
                 .collect(),
         }
@@ -828,6 +860,7 @@ impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
                     .map(|t| Argument {
                         type_: t.clean(cx),
                         name: names.next().map_or(kw::Empty, |i| i.name),
+                        is_const: false,
                     })
                     .collect(),
             },
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 02a4fc5fb65..1267e88f358 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1353,6 +1353,9 @@ crate struct Arguments {
 crate struct Argument {
     crate type_: Type,
     crate name: Symbol,
+    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
+    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
+    crate is_const: bool,
 }
 
 #[derive(Clone, PartialEq, Debug)]
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index fdb52703edf..25471dd726d 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1177,6 +1177,10 @@ impl clean::FnDecl {
                     args.push_str(" <br>");
                     args_plain.push(' ');
                 }
+                if input.is_const {
+                    args.push_str("const ");
+                    args_plain.push_str("const ");
+                }
                 if !input.name.is_empty() {
                     args.push_str(&format!("{}: ", input.name));
                     args_plain.push_str(&format!("{}: ", input.name));
diff --git a/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
index 6a5b88c4a7f..f2b02551146 100644
--- a/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff
+++ b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before SimplifyBranches-after-const-prop
-+ // MIR for `main` after SimplifyBranches-after-const-prop
+- // MIR for `main` before SimplifyConstCondition-after-const-prop
++ // MIR for `main` after SimplifyConstCondition-after-const-prop
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/switch_int.rs:6:11: 6:11
diff --git a/src/test/mir-opt/const_prop/switch_int.rs b/src/test/mir-opt/const_prop/switch_int.rs
index 9e7c7340448..d7319eca18e 100644
--- a/src/test/mir-opt/const_prop/switch_int.rs
+++ b/src/test/mir-opt/const_prop/switch_int.rs
@@ -2,7 +2,7 @@
 fn foo(_: i32) { }
 
 // EMIT_MIR switch_int.main.ConstProp.diff
-// EMIT_MIR switch_int.main.SimplifyBranches-after-const-prop.diff
+// EMIT_MIR switch_int.main.SimplifyConstCondition-after-const-prop.diff
 fn main() {
     match 1 {
         1 => foo(0),
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs
index 02221c4cf4a..ca298e9211d 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.rs
+++ b/src/test/mir-opt/early_otherwise_branch_68867.rs
@@ -11,7 +11,7 @@ pub enum ViewportPercentageLength {
 }
 
 // EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
-// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-final.after
+// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyConstCondition-final.after
 #[no_mangle]
 pub extern "C" fn try_sum(
     x: &ViewportPercentageLength,
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
index f23d035545e..44294030439 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
@@ -1,5 +1,5 @@
 - // MIR for `try_sum` before EarlyOtherwiseBranch
-+ // MIR for `try_sum` after SimplifyBranches-final
++ // MIR for `try_sum` after SimplifyConstCondition-final
   
   fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result<ViewportPercentageLength, ()> {
       debug x => _1;                       // in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:5: 17:6
diff --git a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
index def6f835131..d11c70b1efe 100644
--- a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff
+++ b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before SimplifyBranches-after-const-prop
-+ // MIR for `main` after SimplifyBranches-after-const-prop
+- // MIR for `main` before SimplifyConstCondition-after-const-prop
++ // MIR for `main` after SimplifyConstCondition-after-const-prop
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/simplify_if.rs:5:11: 5:11
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
index 67b2027b710..2d093d9266b 100644
--- a/src/test/mir-opt/simplify_if.rs
+++ b/src/test/mir-opt/simplify_if.rs
@@ -1,7 +1,7 @@
 #[inline(never)]
 fn noop() {}
 
-// EMIT_MIR simplify_if.main.SimplifyBranches-after-const-prop.diff
+// EMIT_MIR simplify_if.main.SimplifyConstCondition-after-const-prop.diff
 fn main() {
     if false {
         noop();
diff --git a/src/test/rustdoc/legacy-const-generic.rs b/src/test/rustdoc/legacy-const-generic.rs
new file mode 100644
index 00000000000..46a50e2fc30
--- /dev/null
+++ b/src/test/rustdoc/legacy-const-generic.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+#![feature(rustc_attrs)]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="rust fn"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1)]
+pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+    [x, Y, z]
+}
+
+// @has 'foo/fn.bar.html'
+// @has - '//*[@class="rust fn"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1, 2)]
+pub fn bar<const Y: usize, const Z: usize>(x: usize) -> [usize; 3] {
+    [x, Y, z]
+}
diff --git a/src/test/ui/consts/drop_zst.rs b/src/test/ui/consts/drop_zst.rs
new file mode 100644
index 00000000000..f7c70d3978b
--- /dev/null
+++ b/src/test/ui/consts/drop_zst.rs
@@ -0,0 +1,17 @@
+// check-fail
+
+#![feature(const_precise_live_drops)]
+
+struct S;
+
+impl Drop for S {
+    fn drop(&mut self) {
+        println!("Hello!");
+    }
+}
+
+const fn foo() {
+    let s = S; //~ destructor
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/drop_zst.stderr b/src/test/ui/consts/drop_zst.stderr
new file mode 100644
index 00000000000..d4be5aa56d9
--- /dev/null
+++ b/src/test/ui/consts/drop_zst.stderr
@@ -0,0 +1,9 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop_zst.rs:14:9
+   |
+LL |     let s = S;
+   |         ^ constant functions cannot evaluate destructors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/expr/if/if-without-block.stderr b/src/test/ui/expr/if/if-without-block.stderr
index ee2bb62e2bb..d3f6ca07617 100644
--- a/src/test/ui/expr/if/if-without-block.stderr
+++ b/src/test/ui/expr/if/if-without-block.stderr
@@ -7,7 +7,11 @@ LL |     if 5 == {
 LL | }
    | ^ expected `{`
    |
-   = help: maybe you forgot the right operand of the condition?
+help: maybe you forgot the right operand of the condition?
+  --> $DIR/if-without-block.rs:3:10
+   |
+LL |     if 5 == {
+   |          ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
new file mode 100644
index 00000000000..5a92bcd37b6
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+trait Trait {
+    type Type;
+}
+
+impl<T> Trait for T {
+    type Type = ();
+}
+
+fn f<'a, 'b>(_: <&'a &'b () as Trait>::Type)
+where
+    'a: 'a,
+    'b: 'b,
+{
+}
+
+fn g<'a, 'b>() {
+    f::<'a, 'b>(());
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-76168-hr-outlives.rs b/src/test/ui/lifetimes/issue-76168-hr-outlives.rs
new file mode 100644
index 00000000000..9366e94c90f
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-76168-hr-outlives.rs
@@ -0,0 +1,19 @@
+// edition:2018
+// check-pass
+
+#![feature(unboxed_closures)]
+use std::future::Future;
+
+async fn wrapper<F>(f: F)
+where for<'a> F: FnOnce<(&'a mut i32,)>,
+    for<'a> <F as FnOnce<(&'a mut i32,)>>::Output: Future<Output=()> + 'a
+{
+    let mut i = 41;
+    f(&mut i).await;
+}
+
+async fn add_one(i: &mut i32) {
+    *i = *i + 1;
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-91421.rs b/src/test/ui/parser/issue-91421.rs
new file mode 100644
index 00000000000..9959df56638
--- /dev/null
+++ b/src/test/ui/parser/issue-91421.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #91421.
+
+fn main() {
+    let value = if true && {
+    //~^ ERROR: this `if` expression has a condition, but no block
+    //~| HELP: maybe you forgot the right operand of the condition?
+        3
+        //~^ ERROR: mismatched types [E0308]
+    } else { 4 };
+}
diff --git a/src/test/ui/parser/issue-91421.stderr b/src/test/ui/parser/issue-91421.stderr
new file mode 100644
index 00000000000..04284d5e3b2
--- /dev/null
+++ b/src/test/ui/parser/issue-91421.stderr
@@ -0,0 +1,21 @@
+error: this `if` expression has a condition, but no block
+  --> $DIR/issue-91421.rs:4:17
+   |
+LL |     let value = if true && {
+   |                 ^^
+   |
+help: maybe you forgot the right operand of the condition?
+  --> $DIR/issue-91421.rs:4:25
+   |
+LL |     let value = if true && {
+   |                         ^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-91421.rs:7:9
+   |
+LL |         3
+   |         ^ expected `bool`, found integer
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/traits/project-modulo-regions.rs b/src/test/ui/traits/project-modulo-regions.rs
new file mode 100644
index 00000000000..f0c0dd3ed95
--- /dev/null
+++ b/src/test/ui/traits/project-modulo-regions.rs
@@ -0,0 +1,55 @@
+// revisions: with_clause without_clause
+// Tests that `EvaluatedToOkModuloRegions` from a projection sub-obligation
+// is correctly propagated
+
+#![feature(rustc_attrs)]
+
+trait MyTrait {
+    type Assoc;
+}
+
+struct MyStruct;
+
+impl MyTrait for MyStruct {
+    // Evaluating this projection will result in `EvaluatedToOkModuloRegions`
+    // (when `with_clause` is enabled)
+    type Assoc = <Bar as MyTrait>::Assoc;
+}
+
+struct Bar;
+
+// The `where` clause on this impl will cause us to produce `EvaluatedToOkModuloRegions`
+// when evaluating a projection involving this impl
+#[cfg(with_clause)]
+impl MyTrait for Bar where for<'b> &'b (): 'b {
+    type Assoc = bool;
+}
+
+// This impl tests that the `EvaluatedToOkModuoRegions` result that we get
+// is really due to the `where` clause on the `with_clause` impl
+#[cfg(without_clause)]
+impl MyTrait for Bar {
+    type Assoc = bool;
+}
+
+// The implementation of `#[rustc_evaluate_where_clauses]` doesn't perform
+// normalization, so we need to place the projection predicate behind a normal
+// trait predicate
+struct Helper {}
+trait HelperTrait {}
+impl HelperTrait for Helper where <MyStruct as MyTrait>::Assoc: Sized {}
+
+// Evaluating this 'where' clause will (recursively) end up evaluating
+// `for<'b> &'b (): 'b`, which will produce `EvaluatedToOkModuloRegions`
+#[rustc_evaluate_where_clauses]
+fn test(val: MyStruct) where Helper: HelperTrait  {
+    panic!()
+}
+
+fn foo(val: MyStruct) {
+    test(val);
+    //[with_clause]~^     ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+    //[without_clause]~^^ ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/project-modulo-regions.with_clause.stderr b/src/test/ui/traits/project-modulo-regions.with_clause.stderr
new file mode 100644
index 00000000000..2434c32c818
--- /dev/null
+++ b/src/test/ui/traits/project-modulo-regions.with_clause.stderr
@@ -0,0 +1,11 @@
+error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+  --> $DIR/project-modulo-regions.rs:50:5
+   |
+LL | fn test(val: MyStruct) where Helper: HelperTrait  {
+   |                                      ----------- predicate
+...
+LL |     test(val);
+   |     ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/project-modulo-regions.without_clause.stderr b/src/test/ui/traits/project-modulo-regions.without_clause.stderr
new file mode 100644
index 00000000000..9d35690d5f0
--- /dev/null
+++ b/src/test/ui/traits/project-modulo-regions.without_clause.stderr
@@ -0,0 +1,11 @@
+error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+  --> $DIR/project-modulo-regions.rs:50:5
+   |
+LL | fn test(val: MyStruct) where Helper: HelperTrait  {
+   |                                      ----------- predicate
+...
+LL |     test(val);
+   |     ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/typeck/issue-91210-ptr-method.fixed b/src/test/ui/typeck/issue-91210-ptr-method.fixed
new file mode 100644
index 00000000000..94200cce73e
--- /dev/null
+++ b/src/test/ui/typeck/issue-91210-ptr-method.fixed
@@ -0,0 +1,15 @@
+// Regression test for issue #91210.
+
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo { read: i32 }
+
+unsafe fn blah(x: *mut Foo) {
+    (*x).read = 4;
+    //~^ ERROR: attempted to take value of method
+    //~| HELP: to access the field, dereference first
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-91210-ptr-method.rs b/src/test/ui/typeck/issue-91210-ptr-method.rs
new file mode 100644
index 00000000000..ed0ce6effe7
--- /dev/null
+++ b/src/test/ui/typeck/issue-91210-ptr-method.rs
@@ -0,0 +1,15 @@
+// Regression test for issue #91210.
+
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo { read: i32 }
+
+unsafe fn blah(x: *mut Foo) {
+    x.read = 4;
+    //~^ ERROR: attempted to take value of method
+    //~| HELP: to access the field, dereference first
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-91210-ptr-method.stderr b/src/test/ui/typeck/issue-91210-ptr-method.stderr
new file mode 100644
index 00000000000..503a32373d5
--- /dev/null
+++ b/src/test/ui/typeck/issue-91210-ptr-method.stderr
@@ -0,0 +1,11 @@
+error[E0615]: attempted to take value of method `read` on type `*mut Foo`
+  --> $DIR/issue-91210-ptr-method.rs:10:7
+   |
+LL |     x.read = 4;
+   |     - ^^^^ method, not a field
+   |     |
+   |     help: to access the field, dereference first: `(*x)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0615`.