133d722a9Sopenharmony_ciuse crate::syntax::atom::Atom::{self, *};
233d722a9Sopenharmony_ciuse crate::syntax::report::Errors;
333d722a9Sopenharmony_ciuse crate::syntax::visit::{self, Visit};
433d722a9Sopenharmony_ciuse crate::syntax::{
533d722a9Sopenharmony_ci    error, ident, trivial, Api, Array, Enum, ExternFn, ExternType, Impl, Lang, Lifetimes,
633d722a9Sopenharmony_ci    NamedType, Ptr, Receiver, Ref, Signature, SliceRef, Struct, Trait, Ty1, Type, TypeAlias, Types,
733d722a9Sopenharmony_ci};
833d722a9Sopenharmony_ciuse proc_macro2::{Delimiter, Group, Ident, TokenStream};
933d722a9Sopenharmony_ciuse quote::{quote, ToTokens};
1033d722a9Sopenharmony_ciuse std::fmt::Display;
1133d722a9Sopenharmony_ciuse syn::{GenericParam, Generics, Lifetime};
1233d722a9Sopenharmony_ci
1333d722a9Sopenharmony_cipub(crate) struct Check<'a> {
1433d722a9Sopenharmony_ci    apis: &'a [Api],
1533d722a9Sopenharmony_ci    types: &'a Types<'a>,
1633d722a9Sopenharmony_ci    errors: &'a mut Errors,
1733d722a9Sopenharmony_ci    generator: Generator,
1833d722a9Sopenharmony_ci}
1933d722a9Sopenharmony_ci
2033d722a9Sopenharmony_cipub(crate) enum Generator {
2133d722a9Sopenharmony_ci    // cxx-build crate, cxxbridge cli, cxx-gen.
2233d722a9Sopenharmony_ci    #[allow(dead_code)]
2333d722a9Sopenharmony_ci    Build,
2433d722a9Sopenharmony_ci    // cxxbridge-macro. This is relevant in that the macro output is going to
2533d722a9Sopenharmony_ci    // get fed straight to rustc, so for errors that rustc already contains
2633d722a9Sopenharmony_ci    // logic to catch (probably with a better diagnostic than what the proc
2733d722a9Sopenharmony_ci    // macro API is able to produce), we avoid duplicating them in our own
2833d722a9Sopenharmony_ci    // diagnostics.
2933d722a9Sopenharmony_ci    #[allow(dead_code)]
3033d722a9Sopenharmony_ci    Macro,
3133d722a9Sopenharmony_ci}
3233d722a9Sopenharmony_ci
3333d722a9Sopenharmony_cipub(crate) fn typecheck(cx: &mut Errors, apis: &[Api], types: &Types, generator: Generator) {
3433d722a9Sopenharmony_ci    do_typecheck(&mut Check {
3533d722a9Sopenharmony_ci        apis,
3633d722a9Sopenharmony_ci        types,
3733d722a9Sopenharmony_ci        errors: cx,
3833d722a9Sopenharmony_ci        generator,
3933d722a9Sopenharmony_ci    });
4033d722a9Sopenharmony_ci}
4133d722a9Sopenharmony_ci
4233d722a9Sopenharmony_cifn do_typecheck(cx: &mut Check) {
4333d722a9Sopenharmony_ci    ident::check_all(cx, cx.apis);
4433d722a9Sopenharmony_ci
4533d722a9Sopenharmony_ci    for ty in cx.types {
4633d722a9Sopenharmony_ci        match ty {
4733d722a9Sopenharmony_ci            Type::Ident(ident) => check_type_ident(cx, ident),
4833d722a9Sopenharmony_ci            Type::RustBox(ptr) => check_type_box(cx, ptr),
4933d722a9Sopenharmony_ci            Type::RustVec(ty) => check_type_rust_vec(cx, ty),
5033d722a9Sopenharmony_ci            Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
5133d722a9Sopenharmony_ci            Type::SharedPtr(ptr) => check_type_shared_ptr(cx, ptr),
5233d722a9Sopenharmony_ci            Type::WeakPtr(ptr) => check_type_weak_ptr(cx, ptr),
5333d722a9Sopenharmony_ci            Type::CxxVector(ptr) => check_type_cxx_vector(cx, ptr),
5433d722a9Sopenharmony_ci            Type::Ref(ty) => check_type_ref(cx, ty),
5533d722a9Sopenharmony_ci            Type::Ptr(ty) => check_type_ptr(cx, ty),
5633d722a9Sopenharmony_ci            Type::Array(array) => check_type_array(cx, array),
5733d722a9Sopenharmony_ci            Type::Fn(ty) => check_type_fn(cx, ty),
5833d722a9Sopenharmony_ci            Type::SliceRef(ty) => check_type_slice_ref(cx, ty),
5933d722a9Sopenharmony_ci            Type::Str(_) | Type::Void(_) => {}
6033d722a9Sopenharmony_ci        }
6133d722a9Sopenharmony_ci    }
6233d722a9Sopenharmony_ci
6333d722a9Sopenharmony_ci    for api in cx.apis {
6433d722a9Sopenharmony_ci        match api {
6533d722a9Sopenharmony_ci            Api::Include(_) => {}
6633d722a9Sopenharmony_ci            Api::Struct(strct) => check_api_struct(cx, strct),
6733d722a9Sopenharmony_ci            Api::Enum(enm) => check_api_enum(cx, enm),
6833d722a9Sopenharmony_ci            Api::CxxType(ety) | Api::RustType(ety) => check_api_type(cx, ety),
6933d722a9Sopenharmony_ci            Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
7033d722a9Sopenharmony_ci            Api::TypeAlias(alias) => check_api_type_alias(cx, alias),
7133d722a9Sopenharmony_ci            Api::Impl(imp) => check_api_impl(cx, imp),
7233d722a9Sopenharmony_ci        }
7333d722a9Sopenharmony_ci    }
7433d722a9Sopenharmony_ci}
7533d722a9Sopenharmony_ci
7633d722a9Sopenharmony_ciimpl Check<'_> {
7733d722a9Sopenharmony_ci    pub(crate) fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
7833d722a9Sopenharmony_ci        self.errors.error(sp, msg);
7933d722a9Sopenharmony_ci    }
8033d722a9Sopenharmony_ci}
8133d722a9Sopenharmony_ci
8233d722a9Sopenharmony_cifn check_type_ident(cx: &mut Check, name: &NamedType) {
8333d722a9Sopenharmony_ci    let ident = &name.rust;
8433d722a9Sopenharmony_ci    if Atom::from(ident).is_none()
8533d722a9Sopenharmony_ci        && !cx.types.structs.contains_key(ident)
8633d722a9Sopenharmony_ci        && !cx.types.enums.contains_key(ident)
8733d722a9Sopenharmony_ci        && !cx.types.cxx.contains(ident)
8833d722a9Sopenharmony_ci        && !cx.types.rust.contains(ident)
8933d722a9Sopenharmony_ci    {
9033d722a9Sopenharmony_ci        let msg = format!("unsupported type: {}", ident);
9133d722a9Sopenharmony_ci        cx.error(ident, msg);
9233d722a9Sopenharmony_ci    }
9333d722a9Sopenharmony_ci}
9433d722a9Sopenharmony_ci
9533d722a9Sopenharmony_cifn check_type_box(cx: &mut Check, ptr: &Ty1) {
9633d722a9Sopenharmony_ci    if let Type::Ident(ident) = &ptr.inner {
9733d722a9Sopenharmony_ci        if cx.types.cxx.contains(&ident.rust)
9833d722a9Sopenharmony_ci            && !cx.types.aliases.contains_key(&ident.rust)
9933d722a9Sopenharmony_ci            && !cx.types.structs.contains_key(&ident.rust)
10033d722a9Sopenharmony_ci            && !cx.types.enums.contains_key(&ident.rust)
10133d722a9Sopenharmony_ci        {
10233d722a9Sopenharmony_ci            cx.error(ptr, error::BOX_CXX_TYPE.msg);
10333d722a9Sopenharmony_ci        }
10433d722a9Sopenharmony_ci
10533d722a9Sopenharmony_ci        if Atom::from(&ident.rust).is_none() {
10633d722a9Sopenharmony_ci            return;
10733d722a9Sopenharmony_ci        }
10833d722a9Sopenharmony_ci    }
10933d722a9Sopenharmony_ci
11033d722a9Sopenharmony_ci    cx.error(ptr, "unsupported target type of Box");
11133d722a9Sopenharmony_ci}
11233d722a9Sopenharmony_ci
11333d722a9Sopenharmony_cifn check_type_rust_vec(cx: &mut Check, ty: &Ty1) {
11433d722a9Sopenharmony_ci    match &ty.inner {
11533d722a9Sopenharmony_ci        Type::Ident(ident) => {
11633d722a9Sopenharmony_ci            if cx.types.cxx.contains(&ident.rust)
11733d722a9Sopenharmony_ci                && !cx.types.aliases.contains_key(&ident.rust)
11833d722a9Sopenharmony_ci                && !cx.types.structs.contains_key(&ident.rust)
11933d722a9Sopenharmony_ci                && !cx.types.enums.contains_key(&ident.rust)
12033d722a9Sopenharmony_ci            {
12133d722a9Sopenharmony_ci                cx.error(ty, "Rust Vec containing C++ type is not supported yet");
12233d722a9Sopenharmony_ci                return;
12333d722a9Sopenharmony_ci            }
12433d722a9Sopenharmony_ci
12533d722a9Sopenharmony_ci            match Atom::from(&ident.rust) {
12633d722a9Sopenharmony_ci                None | Some(Bool) | Some(Char) | Some(U8) | Some(U16) | Some(U32) | Some(U64)
12733d722a9Sopenharmony_ci                | Some(Usize) | Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize)
12833d722a9Sopenharmony_ci                | Some(F32) | Some(F64) | Some(RustString) => return,
12933d722a9Sopenharmony_ci                Some(CxxString) => {}
13033d722a9Sopenharmony_ci            }
13133d722a9Sopenharmony_ci        }
13233d722a9Sopenharmony_ci        Type::Str(_) => return,
13333d722a9Sopenharmony_ci        _ => {}
13433d722a9Sopenharmony_ci    }
13533d722a9Sopenharmony_ci
13633d722a9Sopenharmony_ci    cx.error(ty, "unsupported element type of Vec");
13733d722a9Sopenharmony_ci}
13833d722a9Sopenharmony_ci
13933d722a9Sopenharmony_cifn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
14033d722a9Sopenharmony_ci    if let Type::Ident(ident) = &ptr.inner {
14133d722a9Sopenharmony_ci        if cx.types.rust.contains(&ident.rust) {
14233d722a9Sopenharmony_ci            cx.error(ptr, "unique_ptr of a Rust type is not supported yet");
14333d722a9Sopenharmony_ci            return;
14433d722a9Sopenharmony_ci        }
14533d722a9Sopenharmony_ci
14633d722a9Sopenharmony_ci        match Atom::from(&ident.rust) {
14733d722a9Sopenharmony_ci            None | Some(CxxString) => return,
14833d722a9Sopenharmony_ci            _ => {}
14933d722a9Sopenharmony_ci        }
15033d722a9Sopenharmony_ci    } else if let Type::CxxVector(_) = &ptr.inner {
15133d722a9Sopenharmony_ci        return;
15233d722a9Sopenharmony_ci    }
15333d722a9Sopenharmony_ci
15433d722a9Sopenharmony_ci    cx.error(ptr, "unsupported unique_ptr target type");
15533d722a9Sopenharmony_ci}
15633d722a9Sopenharmony_ci
15733d722a9Sopenharmony_cifn check_type_shared_ptr(cx: &mut Check, ptr: &Ty1) {
15833d722a9Sopenharmony_ci    if let Type::Ident(ident) = &ptr.inner {
15933d722a9Sopenharmony_ci        if cx.types.rust.contains(&ident.rust) {
16033d722a9Sopenharmony_ci            cx.error(ptr, "shared_ptr of a Rust type is not supported yet");
16133d722a9Sopenharmony_ci            return;
16233d722a9Sopenharmony_ci        }
16333d722a9Sopenharmony_ci
16433d722a9Sopenharmony_ci        match Atom::from(&ident.rust) {
16533d722a9Sopenharmony_ci            None | Some(Bool) | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize)
16633d722a9Sopenharmony_ci            | Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32)
16733d722a9Sopenharmony_ci            | Some(F64) | Some(CxxString) => return,
16833d722a9Sopenharmony_ci            Some(Char) | Some(RustString) => {}
16933d722a9Sopenharmony_ci        }
17033d722a9Sopenharmony_ci    } else if let Type::CxxVector(_) = &ptr.inner {
17133d722a9Sopenharmony_ci        cx.error(ptr, "std::shared_ptr<std::vector> is not supported yet");
17233d722a9Sopenharmony_ci        return;
17333d722a9Sopenharmony_ci    }
17433d722a9Sopenharmony_ci
17533d722a9Sopenharmony_ci    cx.error(ptr, "unsupported shared_ptr target type");
17633d722a9Sopenharmony_ci}
17733d722a9Sopenharmony_ci
17833d722a9Sopenharmony_cifn check_type_weak_ptr(cx: &mut Check, ptr: &Ty1) {
17933d722a9Sopenharmony_ci    if let Type::Ident(ident) = &ptr.inner {
18033d722a9Sopenharmony_ci        if cx.types.rust.contains(&ident.rust) {
18133d722a9Sopenharmony_ci            cx.error(ptr, "weak_ptr of a Rust type is not supported yet");
18233d722a9Sopenharmony_ci            return;
18333d722a9Sopenharmony_ci        }
18433d722a9Sopenharmony_ci
18533d722a9Sopenharmony_ci        match Atom::from(&ident.rust) {
18633d722a9Sopenharmony_ci            None | Some(Bool) | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize)
18733d722a9Sopenharmony_ci            | Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32)
18833d722a9Sopenharmony_ci            | Some(F64) | Some(CxxString) => return,
18933d722a9Sopenharmony_ci            Some(Char) | Some(RustString) => {}
19033d722a9Sopenharmony_ci        }
19133d722a9Sopenharmony_ci    } else if let Type::CxxVector(_) = &ptr.inner {
19233d722a9Sopenharmony_ci        cx.error(ptr, "std::weak_ptr<std::vector> is not supported yet");
19333d722a9Sopenharmony_ci        return;
19433d722a9Sopenharmony_ci    }
19533d722a9Sopenharmony_ci
19633d722a9Sopenharmony_ci    cx.error(ptr, "unsupported weak_ptr target type");
19733d722a9Sopenharmony_ci}
19833d722a9Sopenharmony_ci
19933d722a9Sopenharmony_cifn check_type_cxx_vector(cx: &mut Check, ptr: &Ty1) {
20033d722a9Sopenharmony_ci    if let Type::Ident(ident) = &ptr.inner {
20133d722a9Sopenharmony_ci        if cx.types.rust.contains(&ident.rust) {
20233d722a9Sopenharmony_ci            cx.error(
20333d722a9Sopenharmony_ci                ptr,
20433d722a9Sopenharmony_ci                "C++ vector containing a Rust type is not supported yet",
20533d722a9Sopenharmony_ci            );
20633d722a9Sopenharmony_ci            return;
20733d722a9Sopenharmony_ci        }
20833d722a9Sopenharmony_ci
20933d722a9Sopenharmony_ci        match Atom::from(&ident.rust) {
21033d722a9Sopenharmony_ci            None | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize) | Some(I8)
21133d722a9Sopenharmony_ci            | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64)
21233d722a9Sopenharmony_ci            | Some(CxxString) => return,
21333d722a9Sopenharmony_ci            Some(Char) => { /* todo */ }
21433d722a9Sopenharmony_ci            Some(Bool) | Some(RustString) => {}
21533d722a9Sopenharmony_ci        }
21633d722a9Sopenharmony_ci    }
21733d722a9Sopenharmony_ci
21833d722a9Sopenharmony_ci    cx.error(ptr, "unsupported vector element type");
21933d722a9Sopenharmony_ci}
22033d722a9Sopenharmony_ci
22133d722a9Sopenharmony_cifn check_type_ref(cx: &mut Check, ty: &Ref) {
22233d722a9Sopenharmony_ci    if ty.mutable && !ty.pinned {
22333d722a9Sopenharmony_ci        if let Some(requires_pin) = match &ty.inner {
22433d722a9Sopenharmony_ci            Type::Ident(ident) if ident.rust == CxxString || is_opaque_cxx(cx, &ident.rust) => {
22533d722a9Sopenharmony_ci                Some(ident.rust.to_string())
22633d722a9Sopenharmony_ci            }
22733d722a9Sopenharmony_ci            Type::CxxVector(_) => Some("CxxVector<...>".to_owned()),
22833d722a9Sopenharmony_ci            _ => None,
22933d722a9Sopenharmony_ci        } {
23033d722a9Sopenharmony_ci            cx.error(
23133d722a9Sopenharmony_ci                ty,
23233d722a9Sopenharmony_ci                format!(
23333d722a9Sopenharmony_ci                    "mutable reference to C++ type requires a pin -- use Pin<&mut {}>",
23433d722a9Sopenharmony_ci                    requires_pin,
23533d722a9Sopenharmony_ci                ),
23633d722a9Sopenharmony_ci            );
23733d722a9Sopenharmony_ci        }
23833d722a9Sopenharmony_ci    }
23933d722a9Sopenharmony_ci
24033d722a9Sopenharmony_ci    match ty.inner {
24133d722a9Sopenharmony_ci        Type::Fn(_) | Type::Void(_) => {}
24233d722a9Sopenharmony_ci        Type::Ref(_) => {
24333d722a9Sopenharmony_ci            cx.error(ty, "C++ does not allow references to references");
24433d722a9Sopenharmony_ci            return;
24533d722a9Sopenharmony_ci        }
24633d722a9Sopenharmony_ci        _ => return,
24733d722a9Sopenharmony_ci    }
24833d722a9Sopenharmony_ci
24933d722a9Sopenharmony_ci    cx.error(ty, "unsupported reference type");
25033d722a9Sopenharmony_ci}
25133d722a9Sopenharmony_ci
25233d722a9Sopenharmony_cifn check_type_ptr(cx: &mut Check, ty: &Ptr) {
25333d722a9Sopenharmony_ci    match ty.inner {
25433d722a9Sopenharmony_ci        Type::Fn(_) | Type::Void(_) => {}
25533d722a9Sopenharmony_ci        Type::Ref(_) => {
25633d722a9Sopenharmony_ci            cx.error(ty, "C++ does not allow pointer to reference as a type");
25733d722a9Sopenharmony_ci            return;
25833d722a9Sopenharmony_ci        }
25933d722a9Sopenharmony_ci        _ => return,
26033d722a9Sopenharmony_ci    }
26133d722a9Sopenharmony_ci
26233d722a9Sopenharmony_ci    cx.error(ty, "unsupported pointer type");
26333d722a9Sopenharmony_ci}
26433d722a9Sopenharmony_ci
26533d722a9Sopenharmony_cifn check_type_slice_ref(cx: &mut Check, ty: &SliceRef) {
26633d722a9Sopenharmony_ci    let supported = !is_unsized(cx, &ty.inner)
26733d722a9Sopenharmony_ci        || match &ty.inner {
26833d722a9Sopenharmony_ci            Type::Ident(ident) => {
26933d722a9Sopenharmony_ci                cx.types.rust.contains(&ident.rust) || cx.types.aliases.contains_key(&ident.rust)
27033d722a9Sopenharmony_ci            }
27133d722a9Sopenharmony_ci            _ => false,
27233d722a9Sopenharmony_ci        };
27333d722a9Sopenharmony_ci
27433d722a9Sopenharmony_ci    if !supported {
27533d722a9Sopenharmony_ci        let mutable = if ty.mutable { "mut " } else { "" };
27633d722a9Sopenharmony_ci        let mut msg = format!("unsupported &{}[T] element type", mutable);
27733d722a9Sopenharmony_ci        if let Type::Ident(ident) = &ty.inner {
27833d722a9Sopenharmony_ci            if is_opaque_cxx(cx, &ident.rust) {
27933d722a9Sopenharmony_ci                msg += ": opaque C++ type is not supported yet";
28033d722a9Sopenharmony_ci            }
28133d722a9Sopenharmony_ci        }
28233d722a9Sopenharmony_ci        cx.error(ty, msg);
28333d722a9Sopenharmony_ci    }
28433d722a9Sopenharmony_ci}
28533d722a9Sopenharmony_ci
28633d722a9Sopenharmony_cifn check_type_array(cx: &mut Check, ty: &Array) {
28733d722a9Sopenharmony_ci    let supported = !is_unsized(cx, &ty.inner);
28833d722a9Sopenharmony_ci
28933d722a9Sopenharmony_ci    if !supported {
29033d722a9Sopenharmony_ci        cx.error(ty, "unsupported array element type");
29133d722a9Sopenharmony_ci    }
29233d722a9Sopenharmony_ci}
29333d722a9Sopenharmony_ci
29433d722a9Sopenharmony_cifn check_type_fn(cx: &mut Check, ty: &Signature) {
29533d722a9Sopenharmony_ci    if ty.throws {
29633d722a9Sopenharmony_ci        cx.error(ty, "function pointer returning Result is not supported yet");
29733d722a9Sopenharmony_ci    }
29833d722a9Sopenharmony_ci
29933d722a9Sopenharmony_ci    for arg in &ty.args {
30033d722a9Sopenharmony_ci        if let Type::Ptr(_) = arg.ty {
30133d722a9Sopenharmony_ci            if ty.unsafety.is_none() {
30233d722a9Sopenharmony_ci                cx.error(
30333d722a9Sopenharmony_ci                    arg,
30433d722a9Sopenharmony_ci                    "pointer argument requires that the function pointer be marked unsafe",
30533d722a9Sopenharmony_ci                );
30633d722a9Sopenharmony_ci            }
30733d722a9Sopenharmony_ci        }
30833d722a9Sopenharmony_ci    }
30933d722a9Sopenharmony_ci}
31033d722a9Sopenharmony_ci
31133d722a9Sopenharmony_cifn check_api_struct(cx: &mut Check, strct: &Struct) {
31233d722a9Sopenharmony_ci    let name = &strct.name;
31333d722a9Sopenharmony_ci    check_reserved_name(cx, &name.rust);
31433d722a9Sopenharmony_ci    check_lifetimes(cx, &strct.generics);
31533d722a9Sopenharmony_ci
31633d722a9Sopenharmony_ci    if strct.fields.is_empty() {
31733d722a9Sopenharmony_ci        let span = span_for_struct_error(strct);
31833d722a9Sopenharmony_ci        cx.error(span, "structs without any fields are not supported");
31933d722a9Sopenharmony_ci    }
32033d722a9Sopenharmony_ci
32133d722a9Sopenharmony_ci    if cx.types.cxx.contains(&name.rust) {
32233d722a9Sopenharmony_ci        if let Some(ety) = cx.types.untrusted.get(&name.rust) {
32333d722a9Sopenharmony_ci            let msg = "extern shared struct must be declared in an `unsafe extern` block";
32433d722a9Sopenharmony_ci            cx.error(ety, msg);
32533d722a9Sopenharmony_ci        }
32633d722a9Sopenharmony_ci    }
32733d722a9Sopenharmony_ci
32833d722a9Sopenharmony_ci    for derive in &strct.derives {
32933d722a9Sopenharmony_ci        if derive.what == Trait::ExternType {
33033d722a9Sopenharmony_ci            let msg = format!("derive({}) on shared struct is not supported", derive);
33133d722a9Sopenharmony_ci            cx.error(derive, msg);
33233d722a9Sopenharmony_ci        }
33333d722a9Sopenharmony_ci    }
33433d722a9Sopenharmony_ci
33533d722a9Sopenharmony_ci    for field in &strct.fields {
33633d722a9Sopenharmony_ci        if let Type::Fn(_) = field.ty {
33733d722a9Sopenharmony_ci            cx.error(
33833d722a9Sopenharmony_ci                field,
33933d722a9Sopenharmony_ci                "function pointers in a struct field are not implemented yet",
34033d722a9Sopenharmony_ci            );
34133d722a9Sopenharmony_ci        } else if is_unsized(cx, &field.ty) {
34233d722a9Sopenharmony_ci            let desc = describe(cx, &field.ty);
34333d722a9Sopenharmony_ci            let msg = format!("using {} by value is not supported", desc);
34433d722a9Sopenharmony_ci            cx.error(field, msg);
34533d722a9Sopenharmony_ci        }
34633d722a9Sopenharmony_ci    }
34733d722a9Sopenharmony_ci}
34833d722a9Sopenharmony_ci
34933d722a9Sopenharmony_cifn check_api_enum(cx: &mut Check, enm: &Enum) {
35033d722a9Sopenharmony_ci    check_reserved_name(cx, &enm.name.rust);
35133d722a9Sopenharmony_ci    check_lifetimes(cx, &enm.generics);
35233d722a9Sopenharmony_ci
35333d722a9Sopenharmony_ci    if enm.variants.is_empty() && !enm.explicit_repr && !enm.variants_from_header {
35433d722a9Sopenharmony_ci        let span = span_for_enum_error(enm);
35533d722a9Sopenharmony_ci        cx.error(
35633d722a9Sopenharmony_ci            span,
35733d722a9Sopenharmony_ci            "explicit #[repr(...)] is required for enum without any variants",
35833d722a9Sopenharmony_ci        );
35933d722a9Sopenharmony_ci    }
36033d722a9Sopenharmony_ci
36133d722a9Sopenharmony_ci    for derive in &enm.derives {
36233d722a9Sopenharmony_ci        if derive.what == Trait::Default || derive.what == Trait::ExternType {
36333d722a9Sopenharmony_ci            let msg = format!("derive({}) on shared enum is not supported", derive);
36433d722a9Sopenharmony_ci            cx.error(derive, msg);
36533d722a9Sopenharmony_ci        }
36633d722a9Sopenharmony_ci    }
36733d722a9Sopenharmony_ci}
36833d722a9Sopenharmony_ci
36933d722a9Sopenharmony_cifn check_api_type(cx: &mut Check, ety: &ExternType) {
37033d722a9Sopenharmony_ci    check_reserved_name(cx, &ety.name.rust);
37133d722a9Sopenharmony_ci    check_lifetimes(cx, &ety.generics);
37233d722a9Sopenharmony_ci
37333d722a9Sopenharmony_ci    for derive in &ety.derives {
37433d722a9Sopenharmony_ci        if derive.what == Trait::ExternType && ety.lang == Lang::Rust {
37533d722a9Sopenharmony_ci            continue;
37633d722a9Sopenharmony_ci        }
37733d722a9Sopenharmony_ci        let lang = match ety.lang {
37833d722a9Sopenharmony_ci            Lang::Rust => "Rust",
37933d722a9Sopenharmony_ci            Lang::Cxx => "C++",
38033d722a9Sopenharmony_ci        };
38133d722a9Sopenharmony_ci        let msg = format!(
38233d722a9Sopenharmony_ci            "derive({}) on opaque {} type is not supported yet",
38333d722a9Sopenharmony_ci            derive, lang,
38433d722a9Sopenharmony_ci        );
38533d722a9Sopenharmony_ci        cx.error(derive, msg);
38633d722a9Sopenharmony_ci    }
38733d722a9Sopenharmony_ci
38833d722a9Sopenharmony_ci    if !ety.bounds.is_empty() {
38933d722a9Sopenharmony_ci        let bounds = &ety.bounds;
39033d722a9Sopenharmony_ci        let span = quote!(#(#bounds)*);
39133d722a9Sopenharmony_ci        cx.error(span, "extern type bounds are not implemented yet");
39233d722a9Sopenharmony_ci    }
39333d722a9Sopenharmony_ci
39433d722a9Sopenharmony_ci    if let Some(reasons) = cx.types.required_trivial.get(&ety.name.rust) {
39533d722a9Sopenharmony_ci        let msg = format!(
39633d722a9Sopenharmony_ci            "needs a cxx::ExternType impl in order to be used as {}",
39733d722a9Sopenharmony_ci            trivial::as_what(&ety.name, reasons),
39833d722a9Sopenharmony_ci        );
39933d722a9Sopenharmony_ci        cx.error(ety, msg);
40033d722a9Sopenharmony_ci    }
40133d722a9Sopenharmony_ci}
40233d722a9Sopenharmony_ci
40333d722a9Sopenharmony_cifn check_api_fn(cx: &mut Check, efn: &ExternFn) {
40433d722a9Sopenharmony_ci    match efn.lang {
40533d722a9Sopenharmony_ci        Lang::Cxx => {
40633d722a9Sopenharmony_ci            if !efn.generics.params.is_empty() && !efn.trusted {
40733d722a9Sopenharmony_ci                let ref span = span_for_generics_error(efn);
40833d722a9Sopenharmony_ci                cx.error(span, "extern C++ function with lifetimes must be declared in `unsafe extern \"C++\"` block");
40933d722a9Sopenharmony_ci            }
41033d722a9Sopenharmony_ci        }
41133d722a9Sopenharmony_ci        Lang::Rust => {
41233d722a9Sopenharmony_ci            if !efn.generics.params.is_empty() && efn.unsafety.is_none() {
41333d722a9Sopenharmony_ci                let ref span = span_for_generics_error(efn);
41433d722a9Sopenharmony_ci                let message = format!(
41533d722a9Sopenharmony_ci                    "must be `unsafe fn {}` in order to expose explicit lifetimes to C++",
41633d722a9Sopenharmony_ci                    efn.name.rust,
41733d722a9Sopenharmony_ci                );
41833d722a9Sopenharmony_ci                cx.error(span, message);
41933d722a9Sopenharmony_ci            }
42033d722a9Sopenharmony_ci        }
42133d722a9Sopenharmony_ci    }
42233d722a9Sopenharmony_ci
42333d722a9Sopenharmony_ci    check_generics(cx, &efn.sig.generics);
42433d722a9Sopenharmony_ci
42533d722a9Sopenharmony_ci    if let Some(receiver) = &efn.receiver {
42633d722a9Sopenharmony_ci        let ref span = span_for_receiver_error(receiver);
42733d722a9Sopenharmony_ci
42833d722a9Sopenharmony_ci        if receiver.ty.rust == "Self" {
42933d722a9Sopenharmony_ci            let mutability = match receiver.mutable {
43033d722a9Sopenharmony_ci                true => "mut ",
43133d722a9Sopenharmony_ci                false => "",
43233d722a9Sopenharmony_ci            };
43333d722a9Sopenharmony_ci            let msg = format!(
43433d722a9Sopenharmony_ci                "unnamed receiver type is only allowed if the surrounding extern block contains exactly one extern type; use `self: &{mutability}TheType`",
43533d722a9Sopenharmony_ci                mutability = mutability,
43633d722a9Sopenharmony_ci            );
43733d722a9Sopenharmony_ci            cx.error(span, msg);
43833d722a9Sopenharmony_ci        } else if cx.types.enums.contains_key(&receiver.ty.rust) {
43933d722a9Sopenharmony_ci            cx.error(
44033d722a9Sopenharmony_ci                span,
44133d722a9Sopenharmony_ci                "unsupported receiver type; C++ does not allow member functions on enums",
44233d722a9Sopenharmony_ci            );
44333d722a9Sopenharmony_ci        } else if !cx.types.structs.contains_key(&receiver.ty.rust)
44433d722a9Sopenharmony_ci            && !cx.types.cxx.contains(&receiver.ty.rust)
44533d722a9Sopenharmony_ci            && !cx.types.rust.contains(&receiver.ty.rust)
44633d722a9Sopenharmony_ci        {
44733d722a9Sopenharmony_ci            cx.error(span, "unrecognized receiver type");
44833d722a9Sopenharmony_ci        } else if receiver.mutable && !receiver.pinned && is_opaque_cxx(cx, &receiver.ty.rust) {
44933d722a9Sopenharmony_ci            cx.error(
45033d722a9Sopenharmony_ci                span,
45133d722a9Sopenharmony_ci                format!(
45233d722a9Sopenharmony_ci                    "mutable reference to opaque C++ type requires a pin -- use `self: Pin<&mut {}>`",
45333d722a9Sopenharmony_ci                    receiver.ty.rust,
45433d722a9Sopenharmony_ci                ),
45533d722a9Sopenharmony_ci            );
45633d722a9Sopenharmony_ci        }
45733d722a9Sopenharmony_ci    }
45833d722a9Sopenharmony_ci
45933d722a9Sopenharmony_ci    for arg in &efn.args {
46033d722a9Sopenharmony_ci        if let Type::Fn(_) = arg.ty {
46133d722a9Sopenharmony_ci            if efn.lang == Lang::Rust {
46233d722a9Sopenharmony_ci                cx.error(
46333d722a9Sopenharmony_ci                    arg,
46433d722a9Sopenharmony_ci                    "passing a function pointer from C++ to Rust is not implemented yet",
46533d722a9Sopenharmony_ci                );
46633d722a9Sopenharmony_ci            }
46733d722a9Sopenharmony_ci        } else if let Type::Ptr(_) = arg.ty {
46833d722a9Sopenharmony_ci            if efn.sig.unsafety.is_none() {
46933d722a9Sopenharmony_ci                cx.error(
47033d722a9Sopenharmony_ci                    arg,
47133d722a9Sopenharmony_ci                    "pointer argument requires that the function be marked unsafe",
47233d722a9Sopenharmony_ci                );
47333d722a9Sopenharmony_ci            }
47433d722a9Sopenharmony_ci        } else if is_unsized(cx, &arg.ty) {
47533d722a9Sopenharmony_ci            let desc = describe(cx, &arg.ty);
47633d722a9Sopenharmony_ci            let msg = format!("passing {} by value is not supported", desc);
47733d722a9Sopenharmony_ci            cx.error(arg, msg);
47833d722a9Sopenharmony_ci        }
47933d722a9Sopenharmony_ci    }
48033d722a9Sopenharmony_ci
48133d722a9Sopenharmony_ci    if let Some(ty) = &efn.ret {
48233d722a9Sopenharmony_ci        if let Type::Fn(_) = ty {
48333d722a9Sopenharmony_ci            cx.error(ty, "returning a function pointer is not implemented yet");
48433d722a9Sopenharmony_ci        } else if is_unsized(cx, ty) {
48533d722a9Sopenharmony_ci            let desc = describe(cx, ty);
48633d722a9Sopenharmony_ci            let msg = format!("returning {} by value is not supported", desc);
48733d722a9Sopenharmony_ci            cx.error(ty, msg);
48833d722a9Sopenharmony_ci        }
48933d722a9Sopenharmony_ci    }
49033d722a9Sopenharmony_ci
49133d722a9Sopenharmony_ci    if efn.lang == Lang::Cxx {
49233d722a9Sopenharmony_ci        check_mut_return_restriction(cx, efn);
49333d722a9Sopenharmony_ci    }
49433d722a9Sopenharmony_ci}
49533d722a9Sopenharmony_ci
49633d722a9Sopenharmony_cifn check_api_type_alias(cx: &mut Check, alias: &TypeAlias) {
49733d722a9Sopenharmony_ci    check_lifetimes(cx, &alias.generics);
49833d722a9Sopenharmony_ci
49933d722a9Sopenharmony_ci    for derive in &alias.derives {
50033d722a9Sopenharmony_ci        let msg = format!("derive({}) on extern type alias is not supported", derive);
50133d722a9Sopenharmony_ci        cx.error(derive, msg);
50233d722a9Sopenharmony_ci    }
50333d722a9Sopenharmony_ci}
50433d722a9Sopenharmony_ci
50533d722a9Sopenharmony_cifn check_api_impl(cx: &mut Check, imp: &Impl) {
50633d722a9Sopenharmony_ci    let ty = &imp.ty;
50733d722a9Sopenharmony_ci
50833d722a9Sopenharmony_ci    check_lifetimes(cx, &imp.impl_generics);
50933d722a9Sopenharmony_ci
51033d722a9Sopenharmony_ci    if let Some(negative) = imp.negative_token {
51133d722a9Sopenharmony_ci        let span = quote!(#negative #ty);
51233d722a9Sopenharmony_ci        cx.error(span, "negative impl is not supported yet");
51333d722a9Sopenharmony_ci        return;
51433d722a9Sopenharmony_ci    }
51533d722a9Sopenharmony_ci
51633d722a9Sopenharmony_ci    match ty {
51733d722a9Sopenharmony_ci        Type::RustBox(ty)
51833d722a9Sopenharmony_ci        | Type::RustVec(ty)
51933d722a9Sopenharmony_ci        | Type::UniquePtr(ty)
52033d722a9Sopenharmony_ci        | Type::SharedPtr(ty)
52133d722a9Sopenharmony_ci        | Type::WeakPtr(ty)
52233d722a9Sopenharmony_ci        | Type::CxxVector(ty) => {
52333d722a9Sopenharmony_ci            if let Type::Ident(inner) = &ty.inner {
52433d722a9Sopenharmony_ci                if Atom::from(&inner.rust).is_none() {
52533d722a9Sopenharmony_ci                    return;
52633d722a9Sopenharmony_ci                }
52733d722a9Sopenharmony_ci            }
52833d722a9Sopenharmony_ci        }
52933d722a9Sopenharmony_ci        _ => {}
53033d722a9Sopenharmony_ci    }
53133d722a9Sopenharmony_ci
53233d722a9Sopenharmony_ci    cx.error(imp, "unsupported Self type of explicit impl");
53333d722a9Sopenharmony_ci}
53433d722a9Sopenharmony_ci
53533d722a9Sopenharmony_cifn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
53633d722a9Sopenharmony_ci    if efn.sig.unsafety.is_some() {
53733d722a9Sopenharmony_ci        // Unrestricted as long as the function is made unsafe-to-call.
53833d722a9Sopenharmony_ci        return;
53933d722a9Sopenharmony_ci    }
54033d722a9Sopenharmony_ci
54133d722a9Sopenharmony_ci    match &efn.ret {
54233d722a9Sopenharmony_ci        Some(Type::Ref(ty)) if ty.mutable => {}
54333d722a9Sopenharmony_ci        Some(Type::SliceRef(slice)) if slice.mutable => {}
54433d722a9Sopenharmony_ci        _ => return,
54533d722a9Sopenharmony_ci    }
54633d722a9Sopenharmony_ci
54733d722a9Sopenharmony_ci    if let Some(receiver) = &efn.receiver {
54833d722a9Sopenharmony_ci        if receiver.mutable {
54933d722a9Sopenharmony_ci            return;
55033d722a9Sopenharmony_ci        }
55133d722a9Sopenharmony_ci        let resolve = match cx.types.try_resolve(&receiver.ty) {
55233d722a9Sopenharmony_ci            Some(resolve) => resolve,
55333d722a9Sopenharmony_ci            None => return,
55433d722a9Sopenharmony_ci        };
55533d722a9Sopenharmony_ci        if !resolve.generics.lifetimes.is_empty() {
55633d722a9Sopenharmony_ci            return;
55733d722a9Sopenharmony_ci        }
55833d722a9Sopenharmony_ci    }
55933d722a9Sopenharmony_ci
56033d722a9Sopenharmony_ci    struct FindLifetimeMut<'a> {
56133d722a9Sopenharmony_ci        cx: &'a Check<'a>,
56233d722a9Sopenharmony_ci        found: bool,
56333d722a9Sopenharmony_ci    }
56433d722a9Sopenharmony_ci
56533d722a9Sopenharmony_ci    impl<'t, 'a> Visit<'t> for FindLifetimeMut<'a> {
56633d722a9Sopenharmony_ci        fn visit_type(&mut self, ty: &'t Type) {
56733d722a9Sopenharmony_ci            self.found |= match ty {
56833d722a9Sopenharmony_ci                Type::Ref(ty) => ty.mutable,
56933d722a9Sopenharmony_ci                Type::SliceRef(slice) => slice.mutable,
57033d722a9Sopenharmony_ci                Type::Ident(ident) if Atom::from(&ident.rust).is_none() => {
57133d722a9Sopenharmony_ci                    match self.cx.types.try_resolve(ident) {
57233d722a9Sopenharmony_ci                        Some(resolve) => !resolve.generics.lifetimes.is_empty(),
57333d722a9Sopenharmony_ci                        None => true,
57433d722a9Sopenharmony_ci                    }
57533d722a9Sopenharmony_ci                }
57633d722a9Sopenharmony_ci                _ => false,
57733d722a9Sopenharmony_ci            };
57833d722a9Sopenharmony_ci            visit::visit_type(self, ty);
57933d722a9Sopenharmony_ci        }
58033d722a9Sopenharmony_ci    }
58133d722a9Sopenharmony_ci
58233d722a9Sopenharmony_ci    let mut visitor = FindLifetimeMut { cx, found: false };
58333d722a9Sopenharmony_ci
58433d722a9Sopenharmony_ci    for arg in &efn.args {
58533d722a9Sopenharmony_ci        visitor.visit_type(&arg.ty);
58633d722a9Sopenharmony_ci    }
58733d722a9Sopenharmony_ci
58833d722a9Sopenharmony_ci    if visitor.found {
58933d722a9Sopenharmony_ci        return;
59033d722a9Sopenharmony_ci    }
59133d722a9Sopenharmony_ci
59233d722a9Sopenharmony_ci    cx.error(
59333d722a9Sopenharmony_ci        efn,
59433d722a9Sopenharmony_ci        "&mut return type is not allowed unless there is a &mut argument",
59533d722a9Sopenharmony_ci    );
59633d722a9Sopenharmony_ci}
59733d722a9Sopenharmony_ci
59833d722a9Sopenharmony_cifn check_reserved_name(cx: &mut Check, ident: &Ident) {
59933d722a9Sopenharmony_ci    if ident == "Box"
60033d722a9Sopenharmony_ci        || ident == "UniquePtr"
60133d722a9Sopenharmony_ci        || ident == "SharedPtr"
60233d722a9Sopenharmony_ci        || ident == "WeakPtr"
60333d722a9Sopenharmony_ci        || ident == "Vec"
60433d722a9Sopenharmony_ci        || ident == "CxxVector"
60533d722a9Sopenharmony_ci        || ident == "str"
60633d722a9Sopenharmony_ci        || Atom::from(ident).is_some()
60733d722a9Sopenharmony_ci    {
60833d722a9Sopenharmony_ci        cx.error(ident, "reserved name");
60933d722a9Sopenharmony_ci    }
61033d722a9Sopenharmony_ci}
61133d722a9Sopenharmony_ci
61233d722a9Sopenharmony_cifn check_reserved_lifetime(cx: &mut Check, lifetime: &Lifetime) {
61333d722a9Sopenharmony_ci    if lifetime.ident == "static" {
61433d722a9Sopenharmony_ci        match cx.generator {
61533d722a9Sopenharmony_ci            Generator::Macro => { /* rustc already reports this */ }
61633d722a9Sopenharmony_ci            Generator::Build => {
61733d722a9Sopenharmony_ci                cx.error(lifetime, error::RESERVED_LIFETIME);
61833d722a9Sopenharmony_ci            }
61933d722a9Sopenharmony_ci        }
62033d722a9Sopenharmony_ci    }
62133d722a9Sopenharmony_ci}
62233d722a9Sopenharmony_ci
62333d722a9Sopenharmony_cifn check_lifetimes(cx: &mut Check, generics: &Lifetimes) {
62433d722a9Sopenharmony_ci    for lifetime in &generics.lifetimes {
62533d722a9Sopenharmony_ci        check_reserved_lifetime(cx, lifetime);
62633d722a9Sopenharmony_ci    }
62733d722a9Sopenharmony_ci}
62833d722a9Sopenharmony_ci
62933d722a9Sopenharmony_cifn check_generics(cx: &mut Check, generics: &Generics) {
63033d722a9Sopenharmony_ci    for generic_param in &generics.params {
63133d722a9Sopenharmony_ci        if let GenericParam::Lifetime(def) = generic_param {
63233d722a9Sopenharmony_ci            check_reserved_lifetime(cx, &def.lifetime);
63333d722a9Sopenharmony_ci        }
63433d722a9Sopenharmony_ci    }
63533d722a9Sopenharmony_ci}
63633d722a9Sopenharmony_ci
63733d722a9Sopenharmony_cifn is_unsized(cx: &mut Check, ty: &Type) -> bool {
63833d722a9Sopenharmony_ci    match ty {
63933d722a9Sopenharmony_ci        Type::Ident(ident) => {
64033d722a9Sopenharmony_ci            let ident = &ident.rust;
64133d722a9Sopenharmony_ci            ident == CxxString || is_opaque_cxx(cx, ident) || cx.types.rust.contains(ident)
64233d722a9Sopenharmony_ci        }
64333d722a9Sopenharmony_ci        Type::Array(array) => is_unsized(cx, &array.inner),
64433d722a9Sopenharmony_ci        Type::CxxVector(_) | Type::Fn(_) | Type::Void(_) => true,
64533d722a9Sopenharmony_ci        Type::RustBox(_)
64633d722a9Sopenharmony_ci        | Type::RustVec(_)
64733d722a9Sopenharmony_ci        | Type::UniquePtr(_)
64833d722a9Sopenharmony_ci        | Type::SharedPtr(_)
64933d722a9Sopenharmony_ci        | Type::WeakPtr(_)
65033d722a9Sopenharmony_ci        | Type::Ref(_)
65133d722a9Sopenharmony_ci        | Type::Ptr(_)
65233d722a9Sopenharmony_ci        | Type::Str(_)
65333d722a9Sopenharmony_ci        | Type::SliceRef(_) => false,
65433d722a9Sopenharmony_ci    }
65533d722a9Sopenharmony_ci}
65633d722a9Sopenharmony_ci
65733d722a9Sopenharmony_cifn is_opaque_cxx(cx: &mut Check, ty: &Ident) -> bool {
65833d722a9Sopenharmony_ci    cx.types.cxx.contains(ty)
65933d722a9Sopenharmony_ci        && !cx.types.structs.contains_key(ty)
66033d722a9Sopenharmony_ci        && !cx.types.enums.contains_key(ty)
66133d722a9Sopenharmony_ci        && !(cx.types.aliases.contains_key(ty) && cx.types.required_trivial.contains_key(ty))
66233d722a9Sopenharmony_ci}
66333d722a9Sopenharmony_ci
66433d722a9Sopenharmony_cifn span_for_struct_error(strct: &Struct) -> TokenStream {
66533d722a9Sopenharmony_ci    let struct_token = strct.struct_token;
66633d722a9Sopenharmony_ci    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
66733d722a9Sopenharmony_ci    brace_token.set_span(strct.brace_token.span.join());
66833d722a9Sopenharmony_ci    quote!(#struct_token #brace_token)
66933d722a9Sopenharmony_ci}
67033d722a9Sopenharmony_ci
67133d722a9Sopenharmony_cifn span_for_enum_error(enm: &Enum) -> TokenStream {
67233d722a9Sopenharmony_ci    let enum_token = enm.enum_token;
67333d722a9Sopenharmony_ci    let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
67433d722a9Sopenharmony_ci    brace_token.set_span(enm.brace_token.span.join());
67533d722a9Sopenharmony_ci    quote!(#enum_token #brace_token)
67633d722a9Sopenharmony_ci}
67733d722a9Sopenharmony_ci
67833d722a9Sopenharmony_cifn span_for_receiver_error(receiver: &Receiver) -> TokenStream {
67933d722a9Sopenharmony_ci    let ampersand = receiver.ampersand;
68033d722a9Sopenharmony_ci    let lifetime = &receiver.lifetime;
68133d722a9Sopenharmony_ci    let mutability = receiver.mutability;
68233d722a9Sopenharmony_ci    if receiver.shorthand {
68333d722a9Sopenharmony_ci        let var = receiver.var;
68433d722a9Sopenharmony_ci        quote!(#ampersand #lifetime #mutability #var)
68533d722a9Sopenharmony_ci    } else {
68633d722a9Sopenharmony_ci        let ty = &receiver.ty;
68733d722a9Sopenharmony_ci        quote!(#ampersand #lifetime #mutability #ty)
68833d722a9Sopenharmony_ci    }
68933d722a9Sopenharmony_ci}
69033d722a9Sopenharmony_ci
69133d722a9Sopenharmony_cifn span_for_generics_error(efn: &ExternFn) -> TokenStream {
69233d722a9Sopenharmony_ci    let unsafety = efn.unsafety;
69333d722a9Sopenharmony_ci    let fn_token = efn.fn_token;
69433d722a9Sopenharmony_ci    let generics = &efn.generics;
69533d722a9Sopenharmony_ci    quote!(#unsafety #fn_token #generics)
69633d722a9Sopenharmony_ci}
69733d722a9Sopenharmony_ci
69833d722a9Sopenharmony_cifn describe(cx: &mut Check, ty: &Type) -> String {
69933d722a9Sopenharmony_ci    match ty {
70033d722a9Sopenharmony_ci        Type::Ident(ident) => {
70133d722a9Sopenharmony_ci            if cx.types.structs.contains_key(&ident.rust) {
70233d722a9Sopenharmony_ci                "struct".to_owned()
70333d722a9Sopenharmony_ci            } else if cx.types.enums.contains_key(&ident.rust) {
70433d722a9Sopenharmony_ci                "enum".to_owned()
70533d722a9Sopenharmony_ci            } else if cx.types.aliases.contains_key(&ident.rust) {
70633d722a9Sopenharmony_ci                "C++ type".to_owned()
70733d722a9Sopenharmony_ci            } else if cx.types.cxx.contains(&ident.rust) {
70833d722a9Sopenharmony_ci                "opaque C++ type".to_owned()
70933d722a9Sopenharmony_ci            } else if cx.types.rust.contains(&ident.rust) {
71033d722a9Sopenharmony_ci                "opaque Rust type".to_owned()
71133d722a9Sopenharmony_ci            } else if Atom::from(&ident.rust) == Some(CxxString) {
71233d722a9Sopenharmony_ci                "C++ string".to_owned()
71333d722a9Sopenharmony_ci            } else if Atom::from(&ident.rust) == Some(Char) {
71433d722a9Sopenharmony_ci                "C char".to_owned()
71533d722a9Sopenharmony_ci            } else {
71633d722a9Sopenharmony_ci                ident.rust.to_string()
71733d722a9Sopenharmony_ci            }
71833d722a9Sopenharmony_ci        }
71933d722a9Sopenharmony_ci        Type::RustBox(_) => "Box".to_owned(),
72033d722a9Sopenharmony_ci        Type::RustVec(_) => "Vec".to_owned(),
72133d722a9Sopenharmony_ci        Type::UniquePtr(_) => "unique_ptr".to_owned(),
72233d722a9Sopenharmony_ci        Type::SharedPtr(_) => "shared_ptr".to_owned(),
72333d722a9Sopenharmony_ci        Type::WeakPtr(_) => "weak_ptr".to_owned(),
72433d722a9Sopenharmony_ci        Type::Ref(_) => "reference".to_owned(),
72533d722a9Sopenharmony_ci        Type::Ptr(_) => "raw pointer".to_owned(),
72633d722a9Sopenharmony_ci        Type::Str(_) => "&str".to_owned(),
72733d722a9Sopenharmony_ci        Type::CxxVector(_) => "C++ vector".to_owned(),
72833d722a9Sopenharmony_ci        Type::SliceRef(_) => "slice".to_owned(),
72933d722a9Sopenharmony_ci        Type::Fn(_) => "function pointer".to_owned(),
73033d722a9Sopenharmony_ci        Type::Void(_) => "()".to_owned(),
73133d722a9Sopenharmony_ci        Type::Array(_) => "array".to_owned(),
73233d722a9Sopenharmony_ci    }
73333d722a9Sopenharmony_ci}
734