diff options
-rw-r--r-- | Changelog.md | 5 | ||||
-rw-r--r-- | docs/assembly.rst | 13 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 5 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 8 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 9 | ||||
-rw-r--r-- | libsolidity/codegen/Compiler.cpp | 13 | ||||
-rw-r--r-- | libsolidity/codegen/Compiler.h | 6 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 44 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.h | 10 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 23 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 7 | ||||
-rw-r--r-- | solc/CommandLineInterface.cpp | 23 | ||||
-rwxr-xr-x | test/cmdlineTests.sh | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 36 | ||||
-rw-r--r-- | test/libsolidity/SolidityNatspecJSON.cpp | 51 | ||||
-rw-r--r-- | test/libsolidity/SolidityTypes.cpp | 3 | ||||
-rw-r--r-- | test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_offset.sol | 9 | ||||
-rw-r--r-- | test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_slot.sol | 9 | ||||
-rw-r--r-- | test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_function.sol | 9 |
19 files changed, 132 insertions, 153 deletions
diff --git a/Changelog.md b/Changelog.md index aa2dce18..dbb44983 100644 --- a/Changelog.md +++ b/Changelog.md @@ -34,6 +34,7 @@ Breaking Changes: * General: C99-style scoping rules are enforced now. This was already the case in the experimental 0.5.0 mode. * General: Disallow combining hex numbers with unit denominations (e.g. ``0x1e wei``). This was already the case in the experimental 0.5.0 mode. * JSON AST: Remove ``constant`` and ``payable`` fields (the information is encoded in the ``stateMutability`` field). + * Interface: Remove "clone contract" feature. The ``--clone-bin`` and ``--combined-json clone-bin`` commandline options are not available anymore. * Name Resolver: Do not exclude public state variables when looking for conflicting declarations. * Optimizer: Remove the no-op ``PUSH1 0 NOT AND`` sequence. * Parser: Disallow trailing dots that are not followed by a number. @@ -78,8 +79,12 @@ Compiler Features: Bugfixes: * Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum. * Code Generator: Fix allocation of byte arrays (zeroed out too much memory). + * Code Generator: Properly handle negative number literals in ABIEncoderV2. + * Commandline Interface: Correctly handle paths with backslashes on windows. * Fix NatSpec json output for `@notice` and `@dev` tags on contract definitions. + * References Resolver: Do not crash on using ``_slot`` and ``_offset`` suffixes on their own. * References Resolver: Enforce ``storage`` as data location for mappings. + * References Resolver: Properly handle invalid references used together with ``_slot`` and ``_offset``. * References Resolver: Report error instead of assertion fail when FunctionType has an undeclared type as parameter. * Type Checker: Disallow assignments to mappings within tuple assignments as well. * Type Checker: Allow assignments to local variables of mapping types. diff --git a/docs/assembly.rst b/docs/assembly.rst index 5041e72c..91ba076a 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -609,12 +609,21 @@ first. Solidity manages memory in a very simple way: There is a "free memory pointer" at position ``0x40`` in memory. If you want to allocate memory, just use the memory -from that point on and update the pointer accordingly. +starting from where this pointer points at and update it accordingly. +There is no built-in mechanism to release or free allocated memory. +Here is an assembly snippet that can be used for allocating memory:: + + function allocate(length) -> pos { + pos := mload(0x40) + mstore(0x40, add(pos, length)) + } The first 64 bytes of memory can be used as "scratch space" for short-term allocation. The 32 bytes after the free memory pointer (i.e. starting at ``0x60``) is meant to be zero permanently and is used as the initial value for empty dynamic memory arrays. +This means that the allocatable memory starts at ``0x80``, which is the initial value +of the free memory pointer. Elements in memory arrays in Solidity always occupy multiples of 32 bytes (yes, this is even true for ``byte[]``, but not for ``bytes`` and ``string``). Multi-dimensional memory @@ -698,7 +707,7 @@ We consider the runtime bytecode of the following Solidity program:: The following assembly will be generated:: { - mstore(0x40, 0x60) // store the "free memory pointer" + mstore(0x40, 0x80) // store the "free memory pointer" // function dispatcher switch div(calldataload(0), exp(2, 226)) case 0xb3de648b { diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index ba793933..5458c1b0 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -256,6 +256,11 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) string("_slot").size() : string("_offset").size() )); + if (realName.empty()) + { + declarationError(_identifier.location, "In variable names _slot and _offset can only be used as a suffix."); + return size_t(-1); + } declarations = m_resolver.nameFromCurrentScope(realName); } if (declarations.size() != 1) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 7cec7c43..d98d6af1 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -867,6 +867,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); Declaration const* declaration = ref->second.declaration; solAssert(!!declaration, ""); + bool requiresStorage = ref->second.isSlot || ref->second.isOffset; if (auto var = dynamic_cast<VariableDeclaration const*>(declaration)) { if (var->isConstant()) @@ -874,7 +875,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) m_errorReporter.typeError(_identifier.location, "Constant variables not supported by inline assembly."); return size_t(-1); } - else if (ref->second.isSlot || ref->second.isOffset) + else if (requiresStorage) { if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) { @@ -906,6 +907,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); } } + else if (requiresStorage) + { + m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); + return size_t(-1); + } else if (_context == julia::IdentifierContext::LValue) { m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly."); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 4ee5bfcf..3eccc6d4 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1137,7 +1137,14 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ string RationalNumberType::richIdentifier() const { - return "t_rational_" + m_value.numerator().str() + "_by_" + m_value.denominator().str(); + // rational seemingly will put the sign always on the numerator, + // but let just make it deterministic here. + bigint numerator = abs(m_value.numerator()); + bigint denominator = abs(m_value.denominator()); + if (m_value < 0) + return "t_rational_minus_" + numerator.str() + "_by_" + denominator.str(); + else + return "t_rational_" + numerator.str() + "_by_" + denominator.str(); } bool RationalNumberType::operator==(Type const& _other) const diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index d3afada5..55f1d252 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -46,19 +46,6 @@ void Compiler::compileContract( m_context.optimise(m_optimize, m_optimizeRuns); } -void Compiler::compileClone( - ContractDefinition const& _contract, - map<ContractDefinition const*, eth::Assembly const*> const& _contracts -) -{ - solAssert(!_contract.isLibrary(), ""); - ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize); - ContractCompiler cloneCompiler(&runtimeCompiler, m_context, m_optimize); - m_runtimeSub = cloneCompiler.compileClone(_contract, _contracts); - - m_context.optimise(m_optimize, m_optimizeRuns); -} - eth::AssemblyItem Compiler::functionEntryLabel(FunctionDefinition const& _function) const { return m_runtimeContext.functionEntryLabelIfExists(_function); diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index f6865d75..4028ae63 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -50,12 +50,6 @@ public: std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts, bytes const& _metadata ); - /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given - /// contract at runtime, but contains the full creation-time code. - void compileClone( - ContractDefinition const& _contract, - std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts - ); /// @returns Entire assembly. eth::Assembly const& assembly() const { return m_context.assembly(); } /// @returns The entire assembled object (with constructor). diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 2f15a33d..f9493d6d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -94,27 +94,6 @@ size_t ContractCompiler::compileConstructor( } } -size_t ContractCompiler::compileClone( - ContractDefinition const& _contract, - map<ContractDefinition const*, eth::Assembly const*> const& _contracts -) -{ - initializeContext(_contract, _contracts); - - appendInitAndConstructorCode(_contract); - - //@todo determine largest return size of all runtime functions - auto runtimeSub = m_context.addSubroutine(cloneRuntime()); - - // stack contains sub size - m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY; - m_context << u256(0) << Instruction::RETURN; - - appendMissingFunctions(); - - return size_t(runtimeSub.data()); -} - void ContractCompiler::initializeContext( ContractDefinition const& _contract, map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts @@ -980,29 +959,6 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType); } -eth::AssemblyPointer ContractCompiler::cloneRuntime() const -{ - eth::Assembly a; - a << Instruction::CALLDATASIZE; - a << u256(0) << Instruction::DUP1 << Instruction::CALLDATACOPY; - //@todo adjust for larger return values, make this dynamic. - a << u256(0x20) << u256(0) << Instruction::CALLDATASIZE; - a << u256(0); - // this is the address which has to be substituted by the linker. - //@todo implement as special "marker" AssemblyItem. - a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); - a << u256(eth::GasCosts::callGas(m_context.evmVersion()) + 10) << Instruction::GAS << Instruction::SUB; - a << Instruction::DELEGATECALL; - //Propagate error condition (if DELEGATECALL pushes 0 on stack). - a << Instruction::ISZERO; - a << Instruction::ISZERO; - eth::AssemblyItem afterTag = a.appendJumpI().tag(); - a << Instruction::INVALID << afterTag; - //@todo adjust for larger return values, make this dynamic. - a << u256(0x20) << u256(0) << Instruction::RETURN; - return make_shared<eth::Assembly>(a); -} - void ContractCompiler::popScopedVariables(ASTNode const* _node) { unsigned blockHeight = m_scopeStackHeight.at(m_modifierDepth).at(_node); diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 8516ec2c..5fa650b1 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -56,13 +56,6 @@ public: ContractDefinition const& _contract, std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts ); - /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given - /// contract at runtime, but contains the full creation-time code. - /// @returns the identifier of the runtime sub-assembly. - size_t compileClone( - ContractDefinition const& _contract, - std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts - ); private: /// Registers the non-function objects inside the contract with the context and stores the basic @@ -122,9 +115,6 @@ private: void appendStackVariableInitialisation(VariableDeclaration const& _variable); void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); - /// @returns the runtime assembly for clone contracts. - eth::AssemblyPointer cloneRuntime() const; - /// Frees the variables of a certain scope (to be used when leaving). void popScopedVariables(ASTNode const* _node); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 32cb488f..29f9ce7d 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -329,7 +329,6 @@ void CompilerStack::link() { contract.second.object.link(m_libraries); contract.second.runtimeObject.link(m_libraries); - contract.second.cloneObject.link(m_libraries); } } @@ -408,11 +407,6 @@ eth::LinkerObject const& CompilerStack::runtimeObject(string const& _contractNam return contract(_contractName).runtimeObject; } -eth::LinkerObject const& CompilerStack::cloneObject(string const& _contractName) const -{ - return contract(_contractName).cloneObject; -} - /// FIXME: cache this string string CompilerStack::assemblyString(string const& _contractName, StringMap _sourceCodes) const { @@ -767,23 +761,6 @@ void CompilerStack::compileContract( } _compiledContracts[compiledContract.contract] = &compiler->assembly(); - - try - { - if (!_contract.isLibrary()) - { - Compiler cloneCompiler(m_evmVersion, m_optimize, m_optimizeRuns); - cloneCompiler.compileClone(_contract, _compiledContracts); - compiledContract.cloneObject = cloneCompiler.assembledObject(); - } - } - catch (eth::AssemblyException const&) - { - // In some cases (if the constructor requests a runtime function), it is not - // possible to compile the clone. - - // TODO: Report error / warning - } } string const CompilerStack::lastContractName() const diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 7b144660..b7d07ca7 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -190,12 +190,6 @@ public: /// @returns the runtime object for the contract. eth::LinkerObject const& runtimeObject(std::string const& _contractName) const; - /// @returns the bytecode of a contract that uses an already deployed contract via DELEGATECALL. - /// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to - /// substituted by the actual address. Note that this sequence starts end ends in three X - /// characters but can contain anything in between. - eth::LinkerObject const& cloneObject(std::string const& _contractName) const; - /// @returns normal contract assembly items eth::AssemblyItems const* assemblyItems(std::string const& _contractName) const; @@ -258,7 +252,6 @@ private: std::shared_ptr<Compiler> compiler; eth::LinkerObject object; ///< Deployment object (includes the runtime sub-object). eth::LinkerObject runtimeObject; ///< Runtime object. - eth::LinkerObject cloneObject; ///< Clone object (deprecated). std::string metadata; ///< The metadata json that will be hashed into the chain. mutable std::unique_ptr<Json::Value const> abi; mutable std::unique_ptr<Json::Value const> userDocumentation; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 6a768a00..14793759 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -80,7 +80,6 @@ static string const g_strAstJson = "ast-json"; static string const g_strAstCompactJson = "ast-compact-json"; static string const g_strBinary = "bin"; static string const g_strBinaryRuntime = "bin-runtime"; -static string const g_strCloneBinary = "clone-bin"; static string const g_strCombinedJson = "combined-json"; static string const g_strCompactJSON = "compact-format"; static string const g_strContracts = "contracts"; @@ -128,7 +127,6 @@ static string const g_argAstCompactJson = g_strAstCompactJson; static string const g_argAstJson = g_strAstJson; static string const g_argBinary = g_strBinary; static string const g_argBinaryRuntime = g_strBinaryRuntime; -static string const g_argCloneBinary = g_strCloneBinary; static string const g_argCombinedJson = g_strCombinedJson; static string const g_argCompactJSON = g_strCompactJSON; static string const g_argGas = g_strGas; @@ -161,7 +159,6 @@ static set<string> const g_combinedJsonArgs g_strAst, g_strBinary, g_strBinaryRuntime, - g_strCloneBinary, g_strCompactJSON, g_strInterface, g_strMetadata, @@ -213,7 +210,6 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args) g_argAstJson, g_argBinary, g_argBinaryRuntime, - g_argCloneBinary, g_argMetadata, g_argNatspecUser, g_argNatspecDev, @@ -237,16 +233,6 @@ void CommandLineInterface::handleBinary(string const& _contract) cout << m_compiler->object(_contract).toHex() << endl; } } - if (m_args.count(g_argCloneBinary)) - { - if (m_args.count(g_argOutputDir)) - createFile(m_compiler->filesystemFriendlyName(_contract) + ".clone_bin", m_compiler->cloneObject(_contract).toHex()); - else - { - cout << "Clone Binary: " << endl; - cout << m_compiler->cloneObject(_contract).toHex() << endl; - } - } if (m_args.count(g_argBinaryRuntime)) { if (m_args.count(g_argOutputDir)) @@ -275,7 +261,7 @@ void CommandLineInterface::handleBytecode(string const& _contract) { if (m_args.count(g_argOpcodes)) handleOpcode(_contract); - if (m_args.count(g_argBinary) || m_args.count(g_argCloneBinary) || m_args.count(g_argBinaryRuntime)) + if (m_args.count(g_argBinary) || m_args.count(g_argBinaryRuntime)) handleBinary(_contract); } @@ -438,7 +424,7 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings() continue; } - m_sourceCodes[infile.string()] = dev::readFileAsString(infile.string()); + m_sourceCodes[infile.generic_string()] = dev::readFileAsString(infile.string()); path = boost::filesystem::canonical(infile).string(); } m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename()); @@ -631,7 +617,6 @@ Allowed options)", (g_argOpcodes.c_str(), "Opcodes of the contracts.") (g_argBinary.c_str(), "Binary of the contracts in hex.") (g_argBinaryRuntime.c_str(), "Binary of the runtime part of the contracts in hex.") - (g_argCloneBinary.c_str(), "Binary of the clone contracts in hex.") (g_argAbi.c_str(), "ABI specification of the contracts.") (g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.") (g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.") @@ -724,7 +709,7 @@ bool CommandLineInterface::processInput() return ReadCallback::Result{false, "Not a valid file."}; auto contents = dev::readFileAsString(canonicalPath.string()); - m_sourceCodes[path.string()] = contents; + m_sourceCodes[path.generic_string()] = contents; return ReadCallback::Result{true, contents}; } catch (Exception const& _exception) @@ -910,8 +895,6 @@ void CommandLineInterface::handleCombinedJSON() contractData[g_strBinary] = m_compiler->object(contractName).toHex(); if (requests.count(g_strBinaryRuntime)) contractData[g_strBinaryRuntime] = m_compiler->runtimeObject(contractName).toHex(); - if (requests.count(g_strCloneBinary)) - contractData[g_strCloneBinary] = m_compiler->cloneObject(contractName).toHex(); if (requests.count(g_strOpcodes)) contractData[g_strOpcodes] = solidity::disassemble(m_compiler->object(contractName).bytecode); if (requests.count(g_strAsm)) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index bc0ee786..d0296515 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -32,7 +32,7 @@ REPO_ROOT=$(cd $(dirname "$0")/.. && pwd) echo $REPO_ROOT SOLC="$REPO_ROOT/build/solc/solc" -FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,clone-bin,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" +FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" echo "Checking that the bug list is up to date..." "$REPO_ROOT"/scripts/update_bugs_by_version.py diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 9c287e5e..bd1d9de7 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -12527,6 +12527,42 @@ BOOST_AUTO_TEST_CASE(abi_encode_empty_string_v2) 0x00 )); } + +BOOST_AUTO_TEST_CASE(abi_encode_rational) +{ + char const* sourceCode = R"( + // Tests that rational numbers (even negative ones) are encoded properly. + contract C { + function f() public pure returns (bytes memory) { + return abi.encode(1, -2); + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f()"), encodeArgs( + 0x20, + 0x40, u256(1), u256(-2) + )); +} + +BOOST_AUTO_TEST_CASE(abi_encode_rational_v2) +{ + char const* sourceCode = R"( + // Tests that rational numbers (even negative ones) are encoded properly. + pragma experimental ABIEncoderV2; + contract C { + function f() public pure returns (bytes memory) { + return abi.encode(1, -2); + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f()"), encodeArgs( + 0x20, + 0x40, u256(1), u256(-2) + )); +} + BOOST_AUTO_TEST_CASE(abi_encode_call) { char const* sourceCode = R"T( diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 98a3bba9..cc44b578 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -41,6 +41,7 @@ public: void checkNatspec( std::string const& _code, + std::string const& _contractName, std::string const& _expectedDocumentationString, bool _userDocumentation ) @@ -52,9 +53,9 @@ public: Json::Value generatedDocumentation; if (_userDocumentation) - generatedDocumentation = m_compilerStack.natspecUser(m_compilerStack.lastContractName()); + generatedDocumentation = m_compilerStack.natspecUser(_contractName); else - generatedDocumentation = m_compilerStack.natspecDev(m_compilerStack.lastContractName()); + generatedDocumentation = m_compilerStack.natspecDev(_contractName); Json::Value expectedDocumentation; jsonParseStrict(_expectedDocumentationString, expectedDocumentation); BOOST_CHECK_MESSAGE( @@ -93,7 +94,7 @@ BOOST_AUTO_TEST_CASE(user_basic_test) " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; - checkNatspec(sourceCode, natspec, true); + checkNatspec(sourceCode, "test", natspec, true); } BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) @@ -119,8 +120,8 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; - checkNatspec(sourceCode, devNatspec, false); - checkNatspec(sourceCode, userNatspec, true); + checkNatspec(sourceCode, "test", devNatspec, false); + checkNatspec(sourceCode, "test", userNatspec, true); } BOOST_AUTO_TEST_CASE(user_multiline_comment) @@ -140,7 +141,7 @@ BOOST_AUTO_TEST_CASE(user_multiline_comment) " \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" "}}"; - checkNatspec(sourceCode, natspec, true); + checkNatspec(sourceCode, "test", natspec, true); } BOOST_AUTO_TEST_CASE(user_multiple_functions) @@ -171,7 +172,7 @@ BOOST_AUTO_TEST_CASE(user_multiple_functions) " \"sub(int256)\":{ \"notice\": \"Subtracts 3 from `input`\"}" "}}"; - checkNatspec(sourceCode, natspec, true); + checkNatspec(sourceCode, "test", natspec, true); } BOOST_AUTO_TEST_CASE(user_empty_contract) @@ -182,7 +183,7 @@ BOOST_AUTO_TEST_CASE(user_empty_contract) char const* natspec = "{\"methods\":{} }"; - checkNatspec(sourceCode, natspec, true); + checkNatspec(sourceCode, "test", natspec, true); } BOOST_AUTO_TEST_CASE(dev_and_user_no_doc) @@ -201,8 +202,8 @@ BOOST_AUTO_TEST_CASE(dev_and_user_no_doc) char const* devNatspec = "{\"methods\":{}}"; char const* userNatspec = "{\"methods\":{}}"; - checkNatspec(sourceCode, devNatspec, false); - checkNatspec(sourceCode, userNatspec, true); + checkNatspec(sourceCode, "test", devNatspec, false); + checkNatspec(sourceCode, "test", userNatspec, true); } BOOST_AUTO_TEST_CASE(dev_desc_after_nl) @@ -228,7 +229,7 @@ BOOST_AUTO_TEST_CASE(dev_desc_after_nl) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_multiple_params) @@ -253,7 +254,7 @@ BOOST_AUTO_TEST_CASE(dev_multiple_params) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_multiple_params_mixed_whitespace) @@ -276,7 +277,7 @@ BOOST_AUTO_TEST_CASE(dev_multiple_params_mixed_whitespace) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) @@ -302,7 +303,7 @@ BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_multiple_functions) @@ -353,7 +354,7 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_return) @@ -381,7 +382,7 @@ BOOST_AUTO_TEST_CASE(dev_return) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) { @@ -411,7 +412,7 @@ BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } @@ -443,7 +444,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_multiline_comment) @@ -476,7 +477,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_comment) " }\n" "}}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_contract_no_doc) @@ -496,7 +497,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_no_doc) " }\n" "}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_contract_doc) @@ -520,7 +521,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_doc) " }\n" "}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(dev_author_at_function) @@ -546,7 +547,7 @@ BOOST_AUTO_TEST_CASE(dev_author_at_function) " }\n" "}"; - checkNatspec(sourceCode, natspec, false); + checkNatspec(sourceCode, "test", natspec, false); } BOOST_AUTO_TEST_CASE(natspec_notice_without_tag) @@ -569,7 +570,7 @@ BOOST_AUTO_TEST_CASE(natspec_notice_without_tag) } )ABCDEF"; - checkNatspec(sourceCode, natspec, true); + checkNatspec(sourceCode, "test", natspec, true); } BOOST_AUTO_TEST_CASE(natspec_multiline_notice_without_tag) @@ -592,7 +593,7 @@ BOOST_AUTO_TEST_CASE(natspec_multiline_notice_without_tag) } )ABCDEF"; - checkNatspec(sourceCode, natspec, true); + checkNatspec(sourceCode, "test", natspec, true); } BOOST_AUTO_TEST_CASE(empty_comment) @@ -608,7 +609,7 @@ BOOST_AUTO_TEST_CASE(empty_comment) } )ABCDEF"; - checkNatspec(sourceCode, natspec, true); + checkNatspec(sourceCode, "test", natspec, true); } BOOST_AUTO_TEST_CASE(dev_title_at_function_error) diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp index b8b537e5..db0e3b66 100644 --- a/test/libsolidity/SolidityTypes.cpp +++ b/test/libsolidity/SolidityTypes.cpp @@ -157,6 +157,9 @@ BOOST_AUTO_TEST_CASE(type_identifiers) BOOST_CHECK_EQUAL(RationalNumberType(rational(7, 1)).identifier(), "t_rational_7_by_1"); BOOST_CHECK_EQUAL(RationalNumberType(rational(200, 77)).identifier(), "t_rational_200_by_77"); BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, 2 * 77)).identifier(), "t_rational_200_by_77"); + BOOST_CHECK_EQUAL(RationalNumberType(rational(-2 * 200, -2 * 77)).identifier(), "t_rational_200_by_77"); + BOOST_CHECK_EQUAL(RationalNumberType(rational(-2 * 200, 2 * 77)).identifier(), "t_rational_minus_200_by_77"); + BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, -2 * 77)).identifier(), "t_rational_minus_200_by_77"); BOOST_CHECK_EQUAL( StringLiteralType(Literal(SourceLocation{}, Token::StringLiteral, make_shared<string>("abc - def"))).identifier(), "t_stringliteral_196a9142ee0d40e274a6482393c762b16dd8315713207365e1e13d8d85b74fc4" diff --git a/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_offset.sol b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_offset.sol new file mode 100644 index 00000000..ec23a263 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_offset.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure { + assembly { + _offset + } + } +} +// ---- +// DeclarationError: (75-82): In variable names _slot and _offset can only be used as a suffix. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_slot.sol b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_slot.sol new file mode 100644 index 00000000..d493a68a --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_slot.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure { + assembly { + _slot + } + } +} +// ---- +// DeclarationError: (75-80): In variable names _slot and _offset can only be used as a suffix. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_function.sol b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_function.sol new file mode 100644 index 00000000..9165654f --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_function.sol @@ -0,0 +1,9 @@ +contract C { + function f() pure public { + assembly { + let x := f_slot + } + } +} +// ---- +// TypeError: (84-90): The suffixes _offset and _slot can only be used on storage variables. |