pub fn parse_attr<'tcx>(cx: &CodegenCx<'tcx>, attr: &Attribute) -> Option<SpirvAttribute> {
    // Example attributes that we parse here:
    // #[spirv(storage_class = "uniform")]
    // #[spirv(entry = "kernel")]
    let is_spirv = match attr.kind {
        AttrKind::Normal(ref item) => {
            // TODO: We ignore the rest of the path. Is this right?
            let last = item.path.segments.last();
            last.map_or(false, |seg| seg.ident.name == cx.sym.spirv)
        }
        AttrKind::DocComment(..) => false,
    };
    if !is_spirv {
        return None;
    }
    let args = if let Some(args) = attr.meta_item_list() {
        args
    } else {
        cx.tcx
            .sess
            .span_err(attr.span, "#[spirv(..)] attribute must have one argument");
        return None;
    };
    if args.len() != 1 {
        cx.tcx
            .sess
            .span_err(attr.span, "#[spirv(..)] attribute must have one argument");
        return None;
    }
    let arg = &args[0];
    if arg.has_name(cx.sym.builtin) {
        if let Some(builtin_arg) = arg.value_str() {
            match cx.sym.symbol_to_builtin(builtin_arg) {
                Some(builtin) => Some(SpirvAttribute::Builtin(builtin)),
                None => {
                    cx.tcx.sess.span_err(attr.span, "unknown spir-v builtin");
                    None
                }
            }
        } else {
            cx.tcx.sess.span_err(
                attr.span,
                "builtin must have value: #[spirv(builtin = \"..\")]",
            );
            None
        }
    } else if arg.has_name(cx.sym.storage_class) {
        if let Some(storage_arg) = arg.value_str() {
            match cx.sym.symbol_to_storageclass(storage_arg) {
                Some(storage_class) => Some(SpirvAttribute::StorageClass(storage_class)),
                None => {
                    cx.tcx
                        .sess
                        .span_err(attr.span, "unknown spir-v storage class");
                    None
                }
            }
        } else {
            cx.tcx.sess.span_err(
                attr.span,
                "storage_class must have value: #[spirv(storage_class = \"..\")]",
            );
            None
        }
    } else if arg.has_name(cx.sym.entry) {
        if let Some(storage_arg) = arg.value_str() {
            match cx.sym.symbol_to_execution_model(storage_arg) {
                Some(execution_model) => Some(SpirvAttribute::Entry(execution_model)),
                None => {
                    cx.tcx
                        .sess
                        .span_err(attr.span, "unknown spir-v execution model");
                    None
                }
            }
        } else {
            cx.tcx
                .sess
                .span_err(attr.span, "entry must have value: #[spirv(entry = \"..\")]");
            None
        }
    } else if arg.has_name(cx.sym.really_unsafe_ignore_bitcasts) {
        Some(SpirvAttribute::ReallyUnsafeIgnoreBitcasts)
    } else {
        cx.tcx
            .sess
            .span_err(attr.span, "unknown argument to spirv attribute");
        None
    }
}
// Note that we could mark the attr as used via cx.tcx.sess.mark_attr_used(attr), but unused reporting already happens
// even before we get here :(
/// Returns None if this attribute is not a spirv attribute, or if it's malformed (and an error is reported).
Note that we could mark the attr as used via cx.tcx.sess.mark_attr_used(attr), but unused reporting already happens
even before we get here :(
Returns None if this attribute is not a spirv attribute, or if it's malformed (and an error is reported).
Note that we could mark the attr as used via cx . tcx . sess . mark_attr_used ( attr ) but unused reporting already happens even before we get here : ( Returns None if this attribute is not a spirv attribute or if it ' s malformed ( and an error is reported ) .
pub fn parse_attr<'tcx>(cx: &CodegenCx<'tcx>, attr: &Attribute) -> Option<SpirvAttribute> {
    // Example attributes that we parse here:
    // #[spirv(storage_class = "uniform")]
    // #[spirv(entry = "kernel")]
    let is_spirv = match attr.kind {
        AttrKind::Normal(ref item) => {
            // TODO: We ignore the rest of the path. Is this right?
            let last = item.path.segments.last();
            last.map_or(false, |seg| seg.ident.name == cx.sym.spirv)
        }
        AttrKind::DocComment(..) => false,
    };
    if !is_spirv {
        return None;
    }
    let args = if let Some(args) = attr.meta_item_list() {
        args
    } else {
        cx.tcx
            .sess
            .span_err(attr.span, "#[spirv(..)] attribute must have one argument");
        return None;
    };
    if args.len() != 1 {
        cx.tcx
            .sess
            .span_err(attr.span, "#[spirv(..)] attribute must have one argument");
        return None;
    }
    let arg = &args[0];
    if arg.has_name(cx.sym.builtin) {
        if let Some(builtin_arg) = arg.value_str() {
            match cx.sym.symbol_to_builtin(builtin_arg) {
                Some(builtin) => Some(SpirvAttribute::Builtin(builtin)),
                None => {
                    cx.tcx.sess.span_err(attr.span, "unknown spir-v builtin");
                    None
                }
            }
        } else {
            cx.tcx.sess.span_err(
                attr.span,
                "builtin must have value: #[spirv(builtin = \"..\")]",
            );
            None
        }
    } else if arg.has_name(cx.sym.storage_class) {
        if let Some(storage_arg) = arg.value_str() {
            match cx.sym.symbol_to_storageclass(storage_arg) {
                Some(storage_class) => Some(SpirvAttribute::StorageClass(storage_class)),
                None => {
                    cx.tcx
                        .sess
                        .span_err(attr.span, "unknown spir-v storage class");
                    None
                }
            }
        } else {
            cx.tcx.sess.span_err(
                attr.span,
                "storage_class must have value: #[spirv(storage_class = \"..\")]",
            );
            None
        }
    } else if arg.has_name(cx.sym.entry) {
        if let Some(storage_arg) = arg.value_str() {
            match cx.sym.symbol_to_execution_model(storage_arg) {
                Some(execution_model) => Some(SpirvAttribute::Entry(execution_model)),
                None => {
                    cx.tcx
                        .sess
                        .span_err(attr.span, "unknown spir-v execution model");
                    None
                }
            }
        } else {
            cx.tcx
                .sess
                .span_err(attr.span, "entry must have value: #[spirv(entry = \"..\")]");
            None
        }
    } else if arg.has_name(cx.sym.really_unsafe_ignore_bitcasts) {
        Some(SpirvAttribute::ReallyUnsafeIgnoreBitcasts)
    } else {
        cx.tcx
            .sess
            .span_err(attr.span, "unknown argument to spirv attribute");
        None
    }
}
pub fn parse_attr < ' tcx > ( cx : & CodegenCx < ' tcx > , attr : & Attribute ) -> Option < SpirvAttribute > { // Example attributes that we parse here: // #[spirv(storage_class = "uniform")] // #[spirv(entry = "kernel")] let is_spirv = match attr . kind { AttrKind :: Normal ( ref item ) => { // TODO: We ignore the rest of the path. Is this right? let last = item . path . segments . last ( ) ; last . map_or ( false , | seg | seg . ident . name == cx . sym . spirv ) } AttrKind :: DocComment ( .. ) => false , } ; if ! is_spirv { return None ; } let args = if let Some ( args ) = attr . meta_item_list ( ) { args } else { cx . tcx . sess . span_err ( attr . span , " " ) ; return None ; } ; if args . len ( ) != 1 { cx . tcx . sess . span_err ( attr . span , " " ) ; return None ; } let arg = & args [ 0 ] ; if arg . has_name ( cx . sym . builtin ) { if let Some ( builtin_arg ) = arg . value_str ( ) { match cx . sym . symbol_to_builtin ( builtin_arg ) { Some ( builtin ) => Some ( SpirvAttribute :: Builtin ( builtin ) ) , None => { cx . tcx . sess . span_err ( attr . span , " " ) ; None } } } else { cx . tcx . sess . span_err ( attr . span , " \" \" " , ) ; None } } else if arg . has_name ( cx . sym . storage_class ) { if let Some ( storage_arg ) = arg . value_str ( ) { match cx . sym . symbol_to_storageclass ( storage_arg ) { Some ( storage_class ) => Some ( SpirvAttribute :: StorageClass ( storage_class ) ) , None => { cx . tcx . sess . span_err ( attr . span , " " ) ; None } } } else { cx . tcx . sess . span_err ( attr . span , " \" \" " , ) ; None } } else if arg . has_name ( cx . sym . entry ) { if let Some ( storage_arg ) = arg . value_str ( ) { match cx . sym . symbol_to_execution_model ( storage_arg ) { Some ( execution_model ) => Some ( SpirvAttribute :: Entry ( execution_model ) ) , None => { cx . tcx . sess . span_err ( attr . span , " " ) ; None } } } else { cx . tcx . sess . span_err ( attr . span , " \" \" " ) ; None } } else if arg . has_name ( cx . sym . really_unsafe_ignore_bitcasts ) { Some ( SpirvAttribute :: ReallyUnsafeIgnoreBitcasts ) } else { cx . tcx . sess . span_err ( attr . span , " " ) ; None } }
Note that we could mark the attr as used via cx.tcx.sess.mark_attr_used(attr), but unused reporting already happens
even before we get here :(
Returns None if this attribute is not a spirv attribute, or if it's malformed (and an error is reported).
Note that we could mark the attr as used via cx . tcx . sess . mark_attr_used ( attr ) but unused reporting already happens even before we get here : ( Returns None if this attribute is not a spirv attribute or if it ' s malformed ( and an error is reported ) .
cx
&CodegenCx<'tcx>
attr
&Attribute
cx
&CodegenCx<'tcx>
attr
&Attribute