rustclangbindgen

Rust bindgen causes a "is not a valid Ident" error on build


Does anyone know how to start debugging this Rust bindgen indent issue?

stderr thread 'main' panicked at '"vpx_codec_ctx_union_(unnamed_at_/usr/include/vpx/_/vpx_codec_h_206_3)" is not a valid Ident', /home/ignis/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.59/src/fallback.rs:811:9

This is referencing this part of the libvpx header:

/*!\brief Codec context structure
 *
 * All codecs \ref MUST support this context structure fully. In general,
 * this data should be considered private to the codec algorithm, and
 * not be manipulated or examined by the calling application. Applications
 * may reference the 'name' member to get a printable description of the
 * algorithm.
 */
typedef struct vpx_codec_ctx {
  const char *name;             /**< Printable interface name */
  vpx_codec_iface_t *iface;     /**< Interface pointers */
  vpx_codec_err_t err;          /**< Last returned error */
  const char *err_detail;       /**< Detailed info, if available */
  vpx_codec_flags_t init_flags; /**< Flags passed at init time */
  union {
    /**< Decoder Configuration Pointer */
    const struct vpx_codec_dec_cfg *dec;
    /**< Encoder Configuration Pointer */
    const struct vpx_codec_enc_cfg *enc;
    const void *raw;
  } config;               /**< Configuration pointer aliasing union */
  vpx_codec_priv_t *priv; /**< Algorithm private storage */
} vpx_codec_ctx_t;

I see a lot of answers online talking about blacklisting these types, but I can't blacklist this as the context type is needed. It seems like the union type is causing trouble...

Update: Found the relevant part of the vpx-sys docs: https://docs.rs/env-libvpx-sys/5.1.2/vpx_sys

Seems like the library author was able to generate the bindings...


Solution

  • This is the panicking code:

    pub(crate) fn is_ident_start(c: char) -> bool {
        c == '_' || unicode_ident::is_xid_start(c)
    }
    
    pub(crate) fn is_ident_continue(c: char) -> bool {
        unicode_ident::is_xid_continue(c)
    }
    
    fn validate_ident(string: &str, raw: bool) {
        if string.is_empty() {
            panic!("Ident is not allowed to be empty; use Option<Ident>");
        }
    
        if string.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
            panic!("Ident cannot be a number; use Literal instead");
        }
    
        fn ident_ok(string: &str) -> bool {
            let mut chars = string.chars();
            let first = chars.next().unwrap();
            if !is_ident_start(first) {
                return false;
            }
            for ch in chars {
                if !is_ident_continue(ch) {
                    return false;
                }
            }
            true
        }
    
        if !ident_ok(string) {
            panic!("{:?} is not a valid Ident", string);
        }
    
        if raw {
            match string {
                "_" | "super" | "self" | "Self" | "crate" => {
                    panic!("`r#{}` cannot be a raw identifier", string);
                }
                _ => {}
            }
        }
    }
    

    This is just checking if the identifiers have valid characters in them. In this case, ( (and I suspect /) are invalid characters.

    So why is this happening? Take a look at the error message: "vpx_codec_ctx_union_(unnamed_at_/usr/include/vpx/_/vpx_codec_h_206_3)" is not a valid Ident

    Everything in the (unamed...) part shouldn't've gotten to this stage. Doing a search, we find the rust-bindgen issue on this which references the libclang commit that caused the change.

    Specifically, that commit was for Clang 16. Therefore, either downgrade Clang to a version before 16, or update your bindgen crate to v0.62.0 or above (which is when the fix was applied).