fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attribute>, span: Span,
                       fld: &mut MacroExpander) -> T
    where T: MacroGenerable,
{
    // It would almost certainly be cleaner to pass the whole macro invocation in,
    // rather than pulling it apart and marking the tts and the ctxt separately.
    let Mac_ { path, tts, .. } = mac.node;
    let mark = fresh_mark();

    fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, mark: Mrk,
                      attrs: Vec<ast::Attribute>, call_site: Span, fld: &'a mut MacroExpander)
                      -> Option<Box<MacResult + 'a>> {
        // Detect use of feature-gated or invalid attributes on macro invoations
        // since they will not be detected after macro expansion.
        for attr in attrs.iter() {
            feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
                                          &fld.cx.parse_sess.codemap(),
                                          &fld.cx.ecfg.features.unwrap());
        }

        if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
            fld.cx.span_err(path.span, "expected macro name without module separators");
            return None;
        }

        let extname = path.segments[0].identifier.name;
        let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
            extension
        } else {
            let mut err = fld.cx.struct_span_err(path.span,
                                                 &format!("macro undefined: '{}!'", &extname));
            fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
            err.emit();
            return None;
        };

        let ident = ident.unwrap_or(keywords::Invalid.ident());
        match *extension {
            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                if ident.name != keywords::Invalid.name() {
                    let msg =
                        format!("macro {}! expects no ident argument, given '{}'", extname, ident);
                    fld.cx.span_err(path.span, &msg);
                    return None;
                }

                fld.cx.bt_push(ExpnInfo {
                    call_site: call_site,
                    callee: NameAndSpan {
                        format: MacroBang(extname),
                        span: exp_span,
                        allow_internal_unstable: allow_internal_unstable,
                    },
                });

                let marked_tts = mark_tts(&tts, mark);
                Some(expandfun.expand(fld.cx, call_site, &marked_tts))
            }

            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
                if ident.name == keywords::Invalid.name() {
                    fld.cx.span_err(path.span,
                                    &format!("macro {}! expects an ident argument", extname));
                    return None;
                };

                fld.cx.bt_push(ExpnInfo {
                    call_site: call_site,
                    callee: NameAndSpan {
                        format: MacroBang(extname),
                        span: tt_span,
                        allow_internal_unstable: allow_internal_unstable,
                    }
                });

                let marked_tts = mark_tts(&tts, mark);
                Some(expander.expand(fld.cx, call_site, ident, marked_tts))
            }

            MacroRulesTT => {
                if ident.name == keywords::Invalid.name() {
                    fld.cx.span_err(path.span,
                                    &format!("macro {}! expects an ident argument", extname));
                    return None;
                };

                fld.cx.bt_push(ExpnInfo {
                    call_site: call_site,
                    callee: NameAndSpan {
                        format: MacroBang(extname),
                        span: None,
                        // `macro_rules!` doesn't directly allow unstable
                        // (this is orthogonal to whether the macro it creates allows it)
                        allow_internal_unstable: false,
                    }
                });

                // DON'T mark before expansion.
                fld.cx.insert_macro(ast::MacroDef {
                    ident: ident,
                    id: ast::DUMMY_NODE_ID,
                    span: call_site,
                    imported_from: None,
                    use_locally: true,
                    body: tts,
                    export: attr::contains_name(&attrs, "macro_export"),
                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
                    attrs: attrs,
                });

                // macro_rules! has a side effect but expands to nothing.
                fld.cx.bt_pop();
                None
            }

            MultiDecorator(..) | MultiModifier(..) => {
                fld.cx.span_err(path.span,
                                &format!("`{}` can only be used in attributes", extname));
                None
            }
        }
    }

    let opt_expanded = T::make_with(match mac_result(&path, ident, tts, mark, attrs, span, fld) {
        Some(result) => result,
        None => return T::dummy(span),
    });

    let expanded = if let Some(expanded) = opt_expanded {
        expanded
    } else {
        let msg = format!("non-{kind} macro in {kind} position: {name}",
                          name = path.segments[0].identifier.name, kind = T::kind_name());
        fld.cx.span_err(path.span, &msg);
        return T::dummy(span);
    };

    let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
    let configured = marked.fold_with(&mut fld.strip_unconfigured());
    fld.load_macros(&configured);
    let fully_expanded = configured.fold_with(fld);
    fld.cx.bt_pop();
    fully_expanded
}
/// Expand a macro invocation. Returns the result of expansion.
Expand a macro invocation. Returns the result of expansion.
Expand a macro invocation . Returns the result of expansion .
fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attribute>, span: Span,
                       fld: &mut MacroExpander) -> T
    where T: MacroGenerable,
{
    // It would almost certainly be cleaner to pass the whole macro invocation in,
    // rather than pulling it apart and marking the tts and the ctxt separately.
    let Mac_ { path, tts, .. } = mac.node;
    let mark = fresh_mark();
    fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, mark: Mrk,
                      attrs: Vec<ast::Attribute>, call_site: Span, fld: &'a mut MacroExpander)
                      -> Option<Box<MacResult + 'a>> {
        // Detect use of feature-gated or invalid attributes on macro invoations
        // since they will not be detected after macro expansion.
        for attr in attrs.iter() {
            feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
                                          &fld.cx.parse_sess.codemap(),
                                          &fld.cx.ecfg.features.unwrap());
        }
        if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
            fld.cx.span_err(path.span, "expected macro name without module separators");
            return None;
        }
        let extname = path.segments[0].identifier.name;
        let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
            extension
        } else {
            let mut err = fld.cx.struct_span_err(path.span,
                                                 &format!("macro undefined: '{}!'", &extname));
            fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
            err.emit();
            return None;
        };
        let ident = ident.unwrap_or(keywords::Invalid.ident());
        match *extension {
            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                if ident.name != keywords::Invalid.name() {
                    let msg =
                        format!("macro {}! expects no ident argument, given '{}'", extname, ident);
                    fld.cx.span_err(path.span, &msg);
                    return None;
                }
                fld.cx.bt_push(ExpnInfo {
                    call_site: call_site,
                    callee: NameAndSpan {
                        format: MacroBang(extname),
                        span: exp_span,
                        allow_internal_unstable: allow_internal_unstable,
                    },
                });
                let marked_tts = mark_tts(&tts, mark);
                Some(expandfun.expand(fld.cx, call_site, &marked_tts))
            }
            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
                if ident.name == keywords::Invalid.name() {
                    fld.cx.span_err(path.span,
                                    &format!("macro {}! expects an ident argument", extname));
                    return None;
                };
                fld.cx.bt_push(ExpnInfo {
                    call_site: call_site,
                    callee: NameAndSpan {
                        format: MacroBang(extname),
                        span: tt_span,
                        allow_internal_unstable: allow_internal_unstable,
                    }
                });
                let marked_tts = mark_tts(&tts, mark);
                Some(expander.expand(fld.cx, call_site, ident, marked_tts))
            }
            MacroRulesTT => {
                if ident.name == keywords::Invalid.name() {
                    fld.cx.span_err(path.span,
                                    &format!("macro {}! expects an ident argument", extname));
                    return None;
                };
                fld.cx.bt_push(ExpnInfo {
                    call_site: call_site,
                    callee: NameAndSpan {
                        format: MacroBang(extname),
                        span: None,
                        // `macro_rules!` doesn't directly allow unstable
                        // (this is orthogonal to whether the macro it creates allows it)
                        allow_internal_unstable: false,
                    }
                });
                // DON'T mark before expansion.
                fld.cx.insert_macro(ast::MacroDef {
                    ident: ident,
                    id: ast::DUMMY_NODE_ID,
                    span: call_site,
                    imported_from: None,
                    use_locally: true,
                    body: tts,
                    export: attr::contains_name(&attrs, "macro_export"),
                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
                    attrs: attrs,
                });
                // macro_rules! has a side effect but expands to nothing.
                fld.cx.bt_pop();
                None
            }
            MultiDecorator(..) | MultiModifier(..) => {
                fld.cx.span_err(path.span,
                                &format!("`{}` can only be used in attributes", extname));
                None
            }
        }
    }
    let opt_expanded = T::make_with(match mac_result(&path, ident, tts, mark, attrs, span, fld) {
        Some(result) => result,
        None => return T::dummy(span),
    });
    let expanded = if let Some(expanded) = opt_expanded {
        expanded
    } else {
        let msg = format!("non-{kind} macro in {kind} position: {name}",
                          name = path.segments[0].identifier.name, kind = T::kind_name());
        fld.cx.span_err(path.span, &msg);
        return T::dummy(span);
    };
    let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
    let configured = marked.fold_with(&mut fld.strip_unconfigured());
    fld.load_macros(&configured);
    let fully_expanded = configured.fold_with(fld);
    fld.cx.bt_pop();
    fully_expanded
}
fn expand_mac_invoc < T > ( mac : ast :: Mac , ident : Option < Ident > , attrs : Vec < ast :: Attribute > , span : Span , fld : & mut MacroExpander ) -> T where T : MacroGenerable , { // It would almost certainly be cleaner to pass the whole macro invocation in, // rather than pulling it apart and marking the tts and the ctxt separately. let Mac_ { path , tts , .. } = mac . node ; let mark = fresh_mark ( ) ; fn mac_result < ' a > ( path : & ast :: Path , ident : Option < Ident > , tts : Vec < TokenTree > , mark : Mrk , attrs : Vec < ast :: Attribute > , call_site : Span , fld : & ' a mut MacroExpander ) -> Option < Box < MacResult + ' a > > { // Detect use of feature-gated or invalid attributes on macro invoations // since they will not be detected after macro expansion. for attr in attrs . iter ( ) { feature_gate :: check_attribute ( & attr , & fld . cx . parse_sess . span_diagnostic , & fld . cx . parse_sess . codemap ( ) , & fld . cx . ecfg . features . unwrap ( ) ) ; } if path . segments . len ( ) > 1 || path . global || ! path . segments [ 0 ] . parameters . is_empty ( ) { fld . cx . span_err ( path . span , " " ) ; return None ; } let extname = path . segments [ 0 ] . identifier . name ; let extension = if let Some ( extension ) = fld . cx . syntax_env . find ( extname ) { extension } else { let mut err = fld . cx . struct_span_err ( path . span , & format ! ( " " extname ) ) ; fld . cx . suggest_macro_name ( & extname . as_str ( ) , & mut err ) ; err . emit ( ) ; return None ; } ; let ident = ident . unwrap_or ( keywords :: Invalid . ident ( ) ) ; match * extension { NormalTT ( ref expandfun , exp_span , allow_internal_unstable ) => { if ident . name != keywords :: Invalid . name ( ) { let msg = format ! ( " " extname ident ) ; fld . cx . span_err ( path . span , & msg ) ; return None ; } fld . cx . bt_push ( ExpnInfo { call_site : call_site , callee : NameAndSpan { format : MacroBang ( extname ) , span : exp_span , allow_internal_unstable : allow_internal_unstable , } , } ) ; let marked_tts = mark_tts ( & tts , mark ) ; Some ( expandfun . expand ( fld . cx , call_site , & marked_tts ) ) } IdentTT ( ref expander , tt_span , allow_internal_unstable ) => { if ident . name == keywords :: Invalid . name ( ) { fld . cx . span_err ( path . span , & format ! ( " " extname ) ) ; return None ; } ; fld . cx . bt_push ( ExpnInfo { call_site : call_site , callee : NameAndSpan { format : MacroBang ( extname ) , span : tt_span , allow_internal_unstable : allow_internal_unstable , } } ) ; let marked_tts = mark_tts ( & tts , mark ) ; Some ( expander . expand ( fld . cx , call_site , ident , marked_tts ) ) } MacroRulesTT => { if ident . name == keywords :: Invalid . name ( ) { fld . cx . span_err ( path . span , & format ! ( " " extname ) ) ; return None ; } ; fld . cx . bt_push ( ExpnInfo { call_site : call_site , callee : NameAndSpan { format : MacroBang ( extname ) , span : None , // `macro_rules!` doesn't directly allow unstable // (this is orthogonal to whether the macro it creates allows it) allow_internal_unstable : false , } } ) ; // DON'T mark before expansion. fld . cx . insert_macro ( ast :: MacroDef { ident : ident , id : ast :: DUMMY_NODE_ID , span : call_site , imported_from : None , use_locally : true , body : tts , export : attr :: contains_name ( & attrs , " " ) , allow_internal_unstable : attr :: contains_name ( & attrs , " " ) , attrs : attrs , } ) ; // macro_rules! has a side effect but expands to nothing. fld . cx . bt_pop ( ) ; None } MultiDecorator ( .. ) | MultiModifier ( .. ) => { fld . cx . span_err ( path . span , & format ! ( " " extname ) ) ; None } } } let opt_expanded = T :: make_with ( match mac_result ( & path , ident , tts , mark , attrs , span , fld ) { Some ( result ) => result , None => return T :: dummy ( span ) , } ) ; let expanded = if let Some ( expanded ) = opt_expanded { expanded } else { let msg = format ! ( " " name path segments [ 0 ] identifier name kind T kind_name ( ) ) ; fld . cx . span_err ( path . span , & msg ) ; return T :: dummy ( span ) ; } ; let marked = expanded . fold_with ( & mut Marker { mark : mark , expn_id : Some ( fld . cx . backtrace ( ) ) } ) ; let configured = marked . fold_with ( & mut fld . strip_unconfigured ( ) ) ; fld . load_macros ( & configured ) ; let fully_expanded = configured . fold_with ( fld ) ; fld . cx . bt_pop ( ) ; fully_expanded }
Expand a macro invocation.
Expand a macro invocation .
mac
ast::Mac
ident
Option<Ident>
attrs
Vec<ast::Attribute>
span
Span
fld
&mut MacroExpander
mac
ast::Mac
ident
Option<Ident>
attrs
Vec<ast::Attribute>
span
Span
fld
&mut MacroExpander