Skip to content

ICE: invalid utility Yul generated for calldata→storage copy of struct containing function() external member (related to #12057) #16751

@msooseth

Description

@msooseth

Description

Pushing a calldata struct into a storage array — where the struct has a function() external member — produces invalid utility Yul that fails the inline-assembly parse and surfaces as an Internal Compiler Error. The Yul errors are the same shape as #12057 (2-slot stack vs 1-slot storage mismatch for external function pointers feeding a 1-value RHS into a 2-variable declaration), but the codegen path is different: this is a calldata→storage struct copy via .push(), and it triggers on both legacy and --via-ir, so the fix that closed #12057 doesn't cover this shape.

Minimal reproducer

Gist: https://gist.github.com/msooseth/108f50796d4c3656b4e0770f35348e73

contract c {
    struct S { uint16 a; uint16 b; function() external payable d; }
    S[] data;
    function test(S calldata c) public { data.push(c); }
}
$ solc --bin repro.sol            # legacy
$ solc --via-ir --bin repro.sol   # via-IR

Both fail. The relevant errors in the generated Yul are identical in both pipelines:

Error (3812): Variable count mismatch for declaration of "memberValue_0, memberValue_1": 2 variables and 1 values.
Error (7000): Function "read_from_calldatat_function_external_payable$__$returns$__$" expects 1 arguments but got 2.
  • Legacy throws at libsolidity/codegen/CompilerContext.cpp:464 (appendInlineAssembly).
  • via-IR throws at libsolidity/interface/CompilerStack.cpp:866 (loadGeneratedIR).

Diagnostic size can explode

Gist: https://gist.github.com/msooseth/75e4cb4ca4b9d68286aab897c52840f3

The error message embeds the full encoded type in generated Yul function names, and the entire generated prelude is dumped verbatim in the ICE output. With a pathologically deep array type elsewhere in the same struct, a 13-line contract produces a multi-hundred-megabyte error message:

contract c {
    struct S {
        uint16 a;
        uint16 b;
        uint[][][][][][][][][]…[][]  // ~370 nesting levels
                       […][3] c;
        function() external payable d;
    }
    S[] data;
    function test(S calldata c) public returns (uint16) { data.push(c); }
}

Output of solc --bin on this: ~101 MB / ~84,800 lines (vs ~18 KB on the minimal reproducer above — same bug, ~5,600× more text). Each [] level extends the encoded type into the names of utility functions like update_storage_value_offset_0_t_array$_..._dyn_storage(...), and those names are repeated throughout the dumped prelude.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions