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
Description
Pushing a calldata struct into a storage array — where the struct has a
function() externalmember — 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
Both fail. The relevant errors in the generated Yul are identical in both pipelines:
libsolidity/codegen/CompilerContext.cpp:464(appendInlineAssembly).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:
Output of
solc --binon 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 likeupdate_storage_value_offset_0_t_array$_..._dyn_storage(...), and those names are repeated throughout the dumped prelude.Environment
0.8.36-develop.2026.5.18+commit.090bc8ff(top ofdevelop)