diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index e520c586f..ab449a730 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2334,3 +2334,39 @@ string YulUtilFunctions::extractReturndataFunction() }); } +string YulUtilFunctions::copyConstructorArgumentsToMemoryFunction( + ContractDefinition const& _contract, + string const& _creationObjectName +) +{ + string functionName = "copy_arguments_for_constructor_" + + toString(_contract.constructor()->id()) + + "_object_" + + _contract.name() + + "_" + + toString(_contract.id()); + + return m_functionCollector.createFunction(functionName, [&]() { + string returnParams = suffixedVariableNameList("ret_param_",0, _contract.constructor()->parameters().size()); + ABIFunctions abiFunctions(m_evmVersion, m_revertStrings, m_functionCollector); + + return util::Whiskers(R"( + function () -> { + let programSize := datasize("") + let argSize := sub(codesize(), programSize) + + let memoryDataOffset := (argSize) + codecopy(memoryDataOffset, programSize, argSize) + + := (memoryDataOffset, add(memoryDataOffset, argSize)) + } + )") + ("functionName", functionName) + ("retParams", returnParams) + ("object", _creationObjectName) + ("allocate", allocationFunction()) + ("abiDecode", abiFunctions.tupleDecoder(FunctionType(*_contract.constructor()).parameterTypes(), true)) + .render(); + }); +} + diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 9550b9e89..b16eb0672 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -337,6 +337,13 @@ public: /// If returndatacopy() is not supported by the underlying target, a empty array will be returned instead. std::string extractReturndataFunction(); + /// @returns function name that returns constructor arguments copied to memory + /// signature: () -> arguments + std::string copyConstructorArgumentsToMemoryFunction( + ContractDefinition const& _contract, + std::string const& _creationObjectName + ); + private: /// Special case of conversionFunction - handles everything that does not /// use exactly one variable to hold the value. diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 7499d3909..92631ddc2 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -81,7 +81,9 @@ string IRGenerator::generate(ContractDefinition const& _contract) object "" { code { - + + let := () + () } @@ -99,8 +101,25 @@ string IRGenerator::generate(ContractDefinition const& _contract) t("CreationObject", creationObjectName(_contract)); t("memoryInit", memoryInit()); - t("constructor", constructorCode(_contract)); + + FunctionDefinition const* constructor = _contract.constructor(); + t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : ""); + vector constructorParams; + if (constructor && !constructor->parameters().empty()) + { + for (size_t i = 0; i < constructor->parameters().size(); ++i) + constructorParams.emplace_back(m_context.newYulVariable()); + t( + "copyConstructorArguments", + m_utils.copyConstructorArgumentsToMemoryFunction(_contract, creationObjectName(_contract)) + ); + } + t("constructorParams", joinHumanReadable(constructorParams)); + t("constructorHasParams", !constructorParams.empty()); + t("implicitConstructor", implicitConstructorName(_contract)); + t("deploy", deployCode(_contract)); + generateImplicitConstructors(_contract); generateQueuedFunctions(); t("functions", m_context.functionCollector().requestedFunctions()); @@ -238,64 +257,115 @@ string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDec return generator.code(); } -string IRGenerator::constructorCode(ContractDefinition const& _contract) +pair> IRGenerator::evaluateConstructorArguments( + ContractDefinition const& _contract +) { - // Initialization of state variables in base-to-derived order. - solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library."); + map constructorParams; + vector>const *>> baseConstructorArguments; - using boost::adaptors::reverse; + for (ASTPointer const& base: _contract.baseContracts()) + if (FunctionDefinition const* baseConstructor = dynamic_cast( + base->name().annotation().referencedDeclaration + )->constructor(); baseConstructor && base->arguments()) + baseConstructorArguments.emplace_back( + dynamic_cast(baseConstructor->scope()), + base->arguments() + ); - ostringstream out; + if (FunctionDefinition const* constructor = _contract.constructor()) + for (auto const& modifier: constructor->modifiers()) + if (FunctionDefinition const* baseConstructor = dynamic_cast( + modifier->name()->annotation().referencedDeclaration + )->constructor(); baseConstructor && modifier->arguments()) + baseConstructorArguments.emplace_back( + dynamic_cast(baseConstructor->scope()), + modifier->arguments() + ); - FunctionDefinition const* constructor = _contract.constructor(); - if (constructor && !constructor->isPayable()) - out << callValueCheck(); - - for (ContractDefinition const* contract: reverse(_contract.annotation().linearizedBaseContracts)) + IRGeneratorForStatements generator{m_context, m_utils}; + for (auto&& [baseContract, arguments]: baseConstructorArguments) { - out << - "\n// Begin state variable initialization for contract \"" << - contract->name() << - "\" (" << - contract->stateVariables().size() << - " variables)\n"; - - IRGeneratorForStatements generator{m_context, m_utils}; - for (VariableDeclaration const* variable: contract->stateVariables()) - if (!variable->isConstant() && !variable->immutable()) - generator.initializeStateVar(*variable); - out << generator.code(); - - out << "// End state variable initialization for contract \"" << contract->name() << "\".\n"; + solAssert(baseContract && arguments, ""); + if (baseContract->constructor() && !arguments->empty()) + { + vector params; + for (size_t i = 0; i < arguments->size(); ++i) + params.emplace_back(generator.evaluateExpression( + *(arguments->at(i)), + *(baseContract->constructor()->parameters()[i]->type()) + ).commaSeparatedList()); + constructorParams[baseContract] = joinHumanReadable(params); + } } - if (constructor) + return {generator.code(), constructorParams}; +} + +string IRGenerator::initStateVariables(ContractDefinition const& _contract) +{ + IRGeneratorForStatements generator{m_context, m_utils}; + for (VariableDeclaration const* variable: _contract.stateVariables()) + if (!variable->isConstant() && !variable->immutable()) + generator.initializeStateVar(*variable); + + return generator.code(); +} + +void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract) +{ + auto listAllParams = [&]( + map const& baseParams) -> string { - ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); - unsigned paramVars = make_shared(constructor->functionType(false)->parameterTypes())->sizeOnStack(); + vector params; + for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) + if (baseParams.count(contract)) + params.emplace_back(baseParams.at(contract)); + return joinHumanReadable(params); + }; - Whiskers t(R"X( - let programSize := datasize("") - let argSize := sub(codesize(), programSize) + map baseConstructorParams; + for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i) + { + ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i]; + baseConstructorParams.erase(contract); - let memoryDataOffset := (argSize) - codecopy(memoryDataOffset, programSize, argSize) + m_context.functionCollector().createFunction(implicitConstructorName(*contract), [&]() { + Whiskers t(R"( + function () { + + () + + + } + )"); + string params; + if (contract->constructor()) + for (ASTPointer const& varDecl: contract->constructor()->parameters()) + params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); + t("params", params); + string baseParamsString = listAllParams(baseConstructorParams); + t("baseParams", baseParamsString); + t("comma", !params.empty() && !baseParamsString.empty() ? ", " : ""); + t("functionName", implicitConstructorName(*contract)); + pair> evaluatedArgs = evaluateConstructorArguments(*contract); + baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end()); + t("evalBaseArguments", evaluatedArgs.first); + if (i < _contract.annotation().linearizedBaseContracts.size() - 1) + { + t("hasNextConstructor", true); + ContractDefinition const* nextContract = _contract.annotation().linearizedBaseContracts[i + 1]; + t("nextConstructor", implicitConstructorName(*nextContract)); + t("nextParams", listAllParams(baseConstructorParams)); + } + else + t("hasNextConstructor", false); + t("initStateVariables", initStateVariables(*contract)); + t("userDefinedConstructorBody", contract->constructor() ? generate(contract->constructor()->body()) : ""); - (memoryDataOffset, add(memoryDataOffset, argSize)) - - () - )X"); - t("object", creationObjectName(_contract)); - t("allocate", m_utils.allocationFunction()); - t("assignToParams", paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := "); - t("params", suffixedVariableNameList("param_", 0, paramVars)); - t("abiDecode", abiFunctions.tupleDecoder(constructor->functionType(false)->parameterTypes(), true)); - t("constructorName", m_context.enqueueFunctionForCodeGeneration(*constructor)); - - out << t.render(); + return t.render(); + }); } - - return out.str(); } string IRGenerator::deployCode(ContractDefinition const& _contract) @@ -323,6 +393,11 @@ string IRGenerator::runtimeObjectName(ContractDefinition const& _contract) return _contract.name() + "_" + to_string(_contract.id()) + "_deployed"; } +string IRGenerator::implicitConstructorName(ContractDefinition const& _contract) +{ + return "constructor_" + _contract.name() + "_" + to_string(_contract.id()); +} + string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) { Whiskers t(R"X( diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index c4035141c..fde382cd7 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -67,12 +67,29 @@ private: /// Generates code that assigns the initial value of the respective type. std::string generateInitialAssignment(VariableDeclaration const& _varDecl); - std::string constructorCode(ContractDefinition const& _contract); + /// Generates implicit constructors for all contracts in the inheritance hierarchy of + /// @a _contract + /// If there are user defined constructors, their body will be included in implicit constructors body. + void generateImplicitConstructors(ContractDefinition const& _contract); + + /// Evaluates constructor's arguments for all base contracts (listed in inheritance specifiers) of + /// @a _contract + /// @returns Pair of expressions needed to evaluate params and list of parameters in a map contract -> params + std::pair> evaluateConstructorArguments( + ContractDefinition const& _contract + ); + + /// Initializes state variables of + /// @a _contract + /// @returns Source code to initialize state variables + std::string initStateVariables(ContractDefinition const& _contract); + std::string deployCode(ContractDefinition const& _contract); std::string callValueCheck(); std::string creationObjectName(ContractDefinition const& _contract); std::string runtimeObjectName(ContractDefinition const& _contract); + std::string implicitConstructorName(ContractDefinition const& _contract); std::string dispatchRoutine(ContractDefinition const& _contract); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 1a403be04..c572d5d8a 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -169,6 +169,14 @@ void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _va assign(m_context.localVariable(_varDecl), zero); } +IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expression, Type const& _targetType) +{ + _expression.accept(*this); + IRVariable variable{m_context.newYulVariable(), _targetType}; + define(variable, _expression); + return variable; +} + void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement) { if (Expression const* expression = _varDeclStatement.initialValue()) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index c0cf11ba0..b8fafd8b6 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -51,6 +51,9 @@ public: /// Generates code to initialize the given local variable. void initializeLocalVar(VariableDeclaration const& _varDecl); + /// Calculates expression's value and returns variable where it was stored + IRVariable evaluateExpression(Expression const& _expression, Type const& _to); + void endVisit(VariableDeclarationStatement const& _variableDeclaration) override; bool visit(Conditional const& _conditional) override; bool visit(Assignment const& _assignment) override; diff --git a/test/cmdlineTests/standard_eWasm_requested/output.json b/test/cmdlineTests/standard_eWasm_requested/output.json index 0d796bce5..a67539f62 100644 --- a/test/cmdlineTests/standard_eWasm_requested/output.json +++ b/test/cmdlineTests/standard_eWasm_requested/output.json @@ -1,6 +1,8 @@ {"contracts":{"A":{"C":{"ewasm":{"wast":"(module ;; sub-module \"C_2_deployed\" will be encoded as custom section in binary here, but is skipped in text mode. (import \"ethereum\" \"codeCopy\" (func $eth.codeCopy (param i32 i32 i32))) + (import \"ethereum\" \"revert\" (func $eth.revert (param i32 i32))) + (import \"ethereum\" \"getCallValue\" (func $eth.getCallValue (param i32))) (import \"ethereum\" \"finish\" (func $eth.finish (param i32 i32))) (memory $memory (export \"memory\") 1) (export \"main\" (func $main)) @@ -9,27 +11,30 @@ (local $_1 i64) (local $p i64) (local $r i64) - (local $hi i64) - (local $hi_1 i64) - (local $y i64) - (local $hi_2 i64) (local $_2 i64) + (local $z1 i64) + (local $z2 i64) + (local $z3 i64) + (local $_3 i64) (local.set $_1 (i64.const 0)) (local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64))) (local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64))))) (if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then (unreachable))) - (local.set $hi (i64.shl (call $endian_swap_16 (local.get $_1)) (i64.const 16))) - (local.set $hi_1 (i64.shl (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32))) - (local.set $y (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32))))) - (i64.store (i32.wrap_i64 (local.get $r)) (local.get $y)) - (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $y)) - (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $y)) - (local.set $hi_2 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32))) - (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (i64.or (local.get $hi_2) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32))))) - (local.set $_2 (datasize \"C_2_deployed\")) - (call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\"))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2)))) - (call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2)))) + (local.set $_2 (call $endian_swap (local.get $_1))) + (i64.store (i32.wrap_i64 (local.get $r)) (local.get $_2)) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $_2)) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $_2)) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (i64.const 128))) + (call $eth.getCallValue (i32.wrap_i64 (i64.const 0))) + (local.set $z1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0))))) + (local.set $z2 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 8)))))))) + (local.set $z3 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 16)))))))) + (if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 24)))))))))))))) (i64.const 0)) (then + (call $revert (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)))) + (local.set $_3 (datasize \"C_2_deployed\")) + (call $codecopy (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\") (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3)) + (call $return (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3)) ) (func $u256_to_i32 @@ -62,6 +67,22 @@ (local.get $r) ) +(func $codecopy + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (param $z1 i64) + (param $z2 i64) + (param $z3 i64) + (param $z4 i64) + (call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4)))) +) + (func $endian_swap_16 (param $x i64) (result i64) @@ -80,5 +101,39 @@ (local.get $y) ) +(func $endian_swap + (param $x i64) + (result i64) + (local $y i64) + (local $hi i64) + (local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32))) + (local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32))))) + (local.get $y) +) + +(func $return + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))) +) + +(func $revert + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (call $eth.revert (i32.wrap_i64 (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (i32.wrap_i64 (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))) +) + ) "}}}},"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index 78ebe59c3..ba3cb8b2a 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -8,8 +8,12 @@ object \"C_6\" { code { mstore(64, 128) + if callvalue() { revert(0, 0) } + constructor_C_6() codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) return(0, datasize(\"C_6_deployed\")) + function constructor_C_6() + { } } object \"C_6_deployed\" { code { diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 2ceee9da0..99fcc85b9 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -9,15 +9,21 @@ object \"C_6\" { code { mstore(64, 128) + if callvalue() { revert(0, 0) } - // Begin state variable initialization for contract \"C\" (0 variables) - // End state variable initialization for contract \"C\". - + constructor_C_6() codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) return(0, datasize(\"C_6_deployed\")) + function constructor_C_6() { + + + + + } + } object \"C_6_deployed\" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 0e88aa5aa..7c5c7a0be 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -9,15 +9,21 @@ object \"C_10\" { code { mstore(64, 128) + if callvalue() { revert(0, 0) } - // Begin state variable initialization for contract \"C\" (0 variables) - // End state variable initialization for contract \"C\". - + constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) return(0, datasize(\"C_10_deployed\")) + function constructor_C_10() { + + + + + } + } object \"C_10_deployed\" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 256b1e4e1..763be945e 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -9,15 +9,21 @@ object \"C_10\" { code { mstore(64, 128) + if callvalue() { revert(0, 0) } - // Begin state variable initialization for contract \"C\" (0 variables) - // End state variable initialization for contract \"C\". - + constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) return(0, datasize(\"C_10_deployed\")) + function constructor_C_10() { + + + + + } + } object \"C_10_deployed\" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index abb929c19..55b35f138 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -9,15 +9,21 @@ object \"C_10\" { code { mstore(64, 128) + if callvalue() { revert(0, 0) } - // Begin state variable initialization for contract \"C\" (0 variables) - // End state variable initialization for contract \"C\". - + constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) return(0, datasize(\"C_10_deployed\")) + function constructor_C_10() { + + + + + } + } object \"C_10_deployed\" { code { diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 991f9d0fd..289846431 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -9,15 +9,21 @@ object \"C_10\" { code { mstore(64, 128) + if callvalue() { revert(0, 0) } - // Begin state variable initialization for contract \"C\" (0 variables) - // End state variable initialization for contract \"C\". - + constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) return(0, datasize(\"C_10_deployed\")) + function constructor_C_10() { + + + + + } + } object \"C_10_deployed\" { code { diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index ff84b1c32..726c6ccf2 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -9,15 +9,21 @@ object \"C_10\" { code { mstore(64, 128) + if callvalue() { revert(0, 0) } - // Begin state variable initialization for contract \"C\" (0 variables) - // End state variable initialization for contract \"C\". - + constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) return(0, datasize(\"C_10_deployed\")) + function constructor_C_10() { + + + + + } + } object \"C_10_deployed\" { code { diff --git a/test/libsolidity/semanticTests/constructor_ihneritance_init_order_2.sol b/test/libsolidity/semanticTests/constructor_ihneritance_init_order_2.sol new file mode 100644 index 000000000..db5f45560 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor_ihneritance_init_order_2.sol @@ -0,0 +1,14 @@ +contract A { + uint x = 42; + function f() public returns(uint256) { + return x; + } +} +contract B is A { + uint public y = f(); +} +// ==== +// compileViaYul: true +// ---- +// constructor() -> +// y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol new file mode 100644 index 000000000..898edf6ad --- /dev/null +++ b/test/libsolidity/semanticTests/constructor_inheritance_init_order.sol @@ -0,0 +1,17 @@ +contract A { + uint x; + constructor() public { + x = 42; + } + function f() public returns(uint256) { + return x; + } +} +contract B is A { + uint public y = f(); +} +// ==== +// compileViaYul: true +// ---- +// constructor() -> +// y() -> 42 diff --git a/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol new file mode 100644 index 000000000..0ec347963 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor_with_params_diamond_inheritance.sol @@ -0,0 +1,28 @@ +contract A { + uint public i; + uint public k; + + constructor(uint newI, uint newK) public { + i = newI; + k = newK; + } +} +abstract contract B is A { + uint public j; + constructor(uint newJ) public { + j = newJ; + } +} +contract C is A { + constructor(uint newI, uint newK) A(newI, newK) public {} +} +contract D is B, C { + constructor(uint newI, uint newK) B(newI) C(newI, newK + 1) public {} +} +// ==== +// compileViaYul: also +// ---- +// constructor(): 2, 0 -> +// i() -> 2 +// j() -> 2 +// k() -> 1 diff --git a/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol new file mode 100644 index 000000000..3419a9c25 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor_with_params_inheritance.sol @@ -0,0 +1,18 @@ +contract C { + uint public i; + uint public k; + + constructor(uint newI, uint newK) public { + i = newI; + k = newK; + } +} +contract D is C { + constructor(uint newI, uint newK) C(newI, newK + 1) public {} +} +// ==== +// compileViaYul: also +// ---- +// constructor(): 2, 0 -> +// i() -> 2 +// k() -> 1 diff --git a/test/libsolidity/semanticTests/constructor_with_params_inheritance_2.sol b/test/libsolidity/semanticTests/constructor_with_params_inheritance_2.sol new file mode 100644 index 000000000..f2c39e75e --- /dev/null +++ b/test/libsolidity/semanticTests/constructor_with_params_inheritance_2.sol @@ -0,0 +1,15 @@ +contract C { + uint public i; + uint public k; + + constructor(uint newI, uint newK) public { + i = newI; + k = newK; + } +} +contract D is C(2, 1) {} +// ==== +// compileViaYul: also +// ---- +// i() -> 2 +// k() -> 1 diff --git a/test/libsolidity/semanticTests/state_variables_init_order.sol b/test/libsolidity/semanticTests/state_variables_init_order.sol new file mode 100644 index 000000000..ef63a38f9 --- /dev/null +++ b/test/libsolidity/semanticTests/state_variables_init_order.sol @@ -0,0 +1,14 @@ +contract A { + uint public x = 0; + uint y = f(); + function f() public returns (uint256) { + ++x; + return 42; + } +} +contract B is A { +} +// ==== +// compileViaYul: also +// ---- +// x() -> 1 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/state_variables_init_order_2.sol b/test/libsolidity/semanticTests/state_variables_init_order_2.sol new file mode 100644 index 000000000..9bdf9c70c --- /dev/null +++ b/test/libsolidity/semanticTests/state_variables_init_order_2.sol @@ -0,0 +1,18 @@ +contract A { + uint public x = 0; + uint y = f(); + function f() public returns (uint256) { + ++x; + return 42; + } +} +contract B is A { + uint public z; + constructor() public { + z = x; + } +} +// ==== +// compileViaYul: also +// ---- +// z() -> 1 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/state_variables_init_order_3.sol b/test/libsolidity/semanticTests/state_variables_init_order_3.sol new file mode 100644 index 000000000..81a5a693d --- /dev/null +++ b/test/libsolidity/semanticTests/state_variables_init_order_3.sol @@ -0,0 +1,29 @@ +contract A { + uint public a = 42; + uint public b; + uint public c; + constructor(uint x) public { + b = a; + a = x; + } + function f(uint x) public returns (uint256) { c = x * 3; return 23; } +} +contract B is A { + uint public d = f(a); + uint public e = b; + uint public b_a; + uint public b_b; + uint public b_c; + constructor() public A(17) { b_a = a; b_b = b; b_c = c; } +} +// ==== +// compileViaYul: true +// ---- +// a() -> 17 +// b() -> 42 +// c() -> 51 +// b_a() -> 17 +// b_b() -> 42 +// b_c() -> 51 +// d() -> 23 +// e() -> 42