• M
    error: Eliminate error_propagate() with Coccinelle, part 1 · 668f62ec
    Markus Armbruster 提交于
    When all we do with an Error we receive into a local variable is
    propagating to somewhere else, we can just as well receive it there
    right away.  Convert
    
        if (!foo(..., &err)) {
            ...
            error_propagate(errp, err);
            ...
            return ...
        }
    
    to
    
        if (!foo(..., errp)) {
            ...
            ...
            return ...
        }
    
    where nothing else needs @err.  Coccinelle script:
    
        @rule1 forall@
        identifier fun, err, errp, lbl;
        expression list args, args2;
        binary operator op;
        constant c1, c2;
        symbol false;
        @@
             if (
        (
        -        fun(args, &err, args2)
        +        fun(args, errp, args2)
        |
        -        !fun(args, &err, args2)
        +        !fun(args, errp, args2)
        |
        -        fun(args, &err, args2) op c1
        +        fun(args, errp, args2) op c1
        )
                )
             {
                 ... when != err
                     when != lbl:
                     when strict
        -        error_propagate(errp, err);
                 ... when != err
        (
                 return;
        |
                 return c2;
        |
                 return false;
        )
             }
    
        @rule2 forall@
        identifier fun, err, errp, lbl;
        expression list args, args2;
        expression var;
        binary operator op;
        constant c1, c2;
        symbol false;
        @@
        -    var = fun(args, &err, args2);
        +    var = fun(args, errp, args2);
             ... when != err
             if (
        (
                 var
        |
                 !var
        |
                 var op c1
        )
                )
             {
                 ... when != err
                     when != lbl:
                     when strict
        -        error_propagate(errp, err);
                 ... when != err
        (
                 return;
        |
                 return c2;
        |
                 return false;
        |
                 return var;
        )
             }
    
        @depends on rule1 || rule2@
        identifier err;
        @@
        -    Error *err = NULL;
             ... when != err
    
    Not exactly elegant, I'm afraid.
    
    The "when != lbl:" is necessary to avoid transforming
    
             if (fun(args, &err)) {
                 goto out
             }
             ...
         out:
             error_propagate(errp, err);
    
    even though other paths to label out still need the error_propagate().
    For an actual example, see sclp_realize().
    
    Without the "when strict", Coccinelle transforms vfio_msix_setup(),
    incorrectly.  I don't know what exactly "when strict" does, only that
    it helps here.
    
    The match of return is narrower than what I want, but I can't figure
    out how to express "return where the operand doesn't use @err".  For
    an example where it's too narrow, see vfio_intx_enable().
    
    Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
    confused by ARMSSE being used both as typedef and function-like macro
    there.  Converted manually.
    
    Line breaks tidied up manually.  One nested declaration of @local_err
    deleted manually.  Preexisting unwanted blank line dropped in
    hw/riscv/sifive_e.c.
    Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
    Reviewed-by: NEric Blake <eblake@redhat.com>
    Message-Id: <20200707160613.848843-35-armbru@redhat.com>
    668f62ec
block.c 208.1 KB