From 2839a1b0bfc635ce56361033eea95f02b3346422 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic <djordje.mijovic@gmail.com> Date: Fri, 4 Dec 2020 14:17:52 +0100 Subject: [PATCH] [Sol->Yul] Documenting difference in initialization order in case of inheritance. Co-authored-by: Leonardo <leo@ethereum.org> Co-authored-by: Daniel Kirchner <daniel@ekpyron.org> --- docs/ir/ir-breaking-changes.rst | 36 +++++++++++++++++++ .../constructor_inheritance_init_order_3.sol | 12 +++++++ 2 files changed, 48 insertions(+) create mode 100644 test/libsolidity/constructor_inheritance_init_order_3.sol diff --git a/docs/ir/ir-breaking-changes.rst b/docs/ir/ir-breaking-changes.rst index 7ffa49508..ec6126beb 100644 --- a/docs/ir/ir-breaking-changes.rst +++ b/docs/ir/ir-breaking-changes.rst @@ -33,3 +33,39 @@ Consequently, if the padding space within a struct is used to store data (e.g. i } We have the same behavior for implicit delete, for example when array of structs is shortened. + + * The order of contract initialization has changed in case of inheritance. + +The order used to be: + - All state variables are zero-initialized at the beginning. + - Evaluate base constructor arguments from most derived to most base contract. + - Initialize all state variables in the whole inheritance hierarchy from most base to most derived. + - Run the constructor, if present, for all contracts in the linearized hierarchy from most base to most derived. + +New order: + - All state variables are zero-initialized at the beginning. + - Evaluate base constructor arguments from most derived to most base contract. + - For every contract in order from most base to most derived in the linearized hierarchy execute: + 1. State variables are assigned value their initial values, if present at declaration. + 2. Constructor, if present. + +This causes differences in some contracts, for example: +:: + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >0.7.0; + + contract A { + uint x; + constructor() { + x = 42; + } + function f() public view returns(uint256) { + return x; + } + } + contract B is A { + uint public y = f(); + } + +Previously, ``y`` would be set to 0. This is due to the fact that we would first initialize state variables: First, ``x`` is set to 0, and when initializing ``y``, ``f()`` would return 0 causing ``y`` to be 0 as well. +With the new rules, ``y`` will be set to 42. We first initialize ``x`` to 0, then call A's constructor which sets ``x`` to 42. Finally, when initializing ``y``, ``f()`` returns 42 causing ``y`` to be 42. diff --git a/test/libsolidity/constructor_inheritance_init_order_3.sol b/test/libsolidity/constructor_inheritance_init_order_3.sol new file mode 100644 index 000000000..c9719a108 --- /dev/null +++ b/test/libsolidity/constructor_inheritance_init_order_3.sol @@ -0,0 +1,12 @@ +contract A { + uint public x; + constructor(uint) {} + function f() public { x = 4; } +} +contract B is A { + constructor() A(f()) {} +} +// ==== +// compileViaYul: also +// ---- +// x() -> 4