diff --git a/syntax/check.rs b/syntax/check.rs index 807847c02..591e53da9 100644 --- a/syntax/check.rs +++ b/syntax/check.rs @@ -1,5 +1,6 @@ use crate::syntax::atom::Atom::{self, *}; use crate::syntax::report::Errors; +use crate::syntax::visit::{self, Visit}; use crate::syntax::{ error, ident, trivial, Api, Array, Enum, ExternFn, ExternType, Impl, Lang, NamedType, Ptr, Receiver, Ref, Signature, SliceRef, Struct, Trait, Ty1, Type, TypeAlias, Types, @@ -518,20 +519,45 @@ fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) { _ => return, } - if let Some(r) = &efn.receiver { - if r.mutable { + if let Some(receiver) = &efn.receiver { + if receiver.mutable { + return; + } + let resolve = cx.types.resolve(&receiver.ty); + if !resolve.generics.lifetimes.is_empty() { return; } } - for arg in &efn.args { - if let Type::Ref(ty) = &arg.ty { - if ty.mutable { - return; - } + struct FindLifetimeMut<'a> { + cx: &'a Check<'a>, + found: bool, + } + + impl<'t, 'a> Visit<'t> for FindLifetimeMut<'a> { + fn visit_type(&mut self, ty: &'t Type) { + self.found |= match ty { + Type::Ref(ty) => ty.mutable, + Type::Ident(ident) => { + let resolve = self.cx.types.resolve(ident); + !resolve.generics.lifetimes.is_empty() + } + _ => false, + }; + visit::visit_type(self, ty); } } + let mut visitor = FindLifetimeMut { cx, found: false }; + + for arg in &efn.args { + visitor.visit_type(&arg.ty); + } + + if visitor.found { + return; + } + cx.error( efn, "&mut return type is not allowed unless there is a &mut argument", diff --git a/tests/ui/mut_return.rs b/tests/ui/mut_return.rs index 74a5c6960..aef3680b9 100644 --- a/tests/ui/mut_return.rs +++ b/tests/ui/mut_return.rs @@ -1,10 +1,16 @@ #[cxx::bridge] mod ffi { + extern "Rust" { + type Mut<'a>; + } + unsafe extern "C++" { type Thing; fn f(t: &Thing) -> Pin<&mut CxxString>; unsafe fn g(t: &Thing) -> Pin<&mut CxxString>; + fn h(t: Box) -> Pin<&mut CxxString>; + fn i<'a>(t: Box>) -> Pin<&'a mut CxxString>; } } diff --git a/tests/ui/mut_return.stderr b/tests/ui/mut_return.stderr index d6ddb88b8..5845eb8ae 100644 --- a/tests/ui/mut_return.stderr +++ b/tests/ui/mut_return.stderr @@ -1,5 +1,5 @@ error: &mut return type is not allowed unless there is a &mut argument - --> $DIR/mut_return.rs:6:9 - | -6 | fn f(t: &Thing) -> Pin<&mut CxxString>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/mut_return.rs:10:9 + | +10 | fn f(t: &Thing) -> Pin<&mut CxxString>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^