aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml2
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md38
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md37
-rw-r--r--.github/ISSUE_TEMPLATE/general.md19
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md (renamed from PULL_REQUEST_TEMPLATE.md)0
-rw-r--r--Changelog.md6
-rw-r--r--cmake/EthOptions.cmake4
-rw-r--r--codecov.yml18
-rw-r--r--docs/assembly.rst13
-rw-r--r--libdevcore/CommonIO.cpp20
-rw-r--r--libdevcore/CommonIO.h6
-rw-r--r--libevmasm/RuleList.h2
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp219
-rw-r--r--libsolidity/analysis/TypeChecker.cpp15
-rw-r--r--libsolidity/analysis/TypeChecker.h1
-rw-r--r--libsolidity/ast/AST.cpp5
-rw-r--r--libsolidity/ast/AST.h1
-rw-r--r--libsolidity/ast/Types.cpp18
-rw-r--r--libsolidity/ast/Types.h4
-rw-r--r--libsolidity/codegen/Compiler.cpp13
-rw-r--r--libsolidity/codegen/Compiler.h6
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp44
-rw-r--r--libsolidity/codegen/ContractCompiler.h10
-rw-r--r--libsolidity/interface/CompilerStack.cpp48
-rw-r--r--libsolidity/interface/CompilerStack.h14
-rw-r--r--solc/CommandLineInterface.cpp23
-rwxr-xr-xtest/cmdlineTests.sh2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp80
-rw-r--r--test/libsolidity/SolidityNatspecJSON.cpp51
-rw-r--r--test/libsolidity/SolidityTypes.cpp3
-rw-r--r--test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_offset.sol9
-rw-r--r--test/libsolidity/syntaxTests/inlineAssembly/storage_reference_empty_slot.sol9
-rw-r--r--test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_function.sol9
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/422_interface_enums.sol1
-rw-r--r--test/libsolidity/syntaxTests/parsing/enum_from_interface.sol9
-rw-r--r--test/libsolidity/syntaxTests/parsing/enum_from_interface_in_library.sol12
-rw-r--r--test/libsolidity/syntaxTests/parsing/enum_from_library.sol9
-rw-r--r--test/libsolidity/syntaxTests/parsing/enum_inheritance_contract.sol9
-rw-r--r--test/libsolidity/syntaxTests/parsing/enum_inheritance_interface.sol9
39 files changed, 482 insertions, 316 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index a2e34b37..e3596d2b 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -200,7 +200,7 @@ jobs:
command: build/test/soltest -t 'syntaxTest*' -- --no-ipc --testpath test
- run:
name: Coverage of type checker
- command: codecov --flags type_checker --gcov-root build
+ command: codecov --flags syntax --gcov-root build
- run: *run_tests
- run:
name: Coverage of all
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..196cbb32
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug Report
+about: Bug reports about the Solidity Compiler.
+---
+
+## Prerequisites
+
+- First, many thanks for taking part in the community. We really appreciate that.
+- We realize there is a lot of data requested here. We ask only that you do your best to provide as much information as possible so we can better help you.
+- Support questions are better asked in one of the following locations:
+ - [Solidity chat](https://gitter.im/ethereum/solidity)
+ - [Stack Overflow](https://ethereum.stackexchange.com/)
+- Ensure the issue isn't already reported.
+- The issue should be reproducible with the latest solidity version , however, this isn't a hard requirement and being reproducible with an older version is sufficient.
+
+*Delete the above section and the instructions in the sections below before submitting*
+
+## Description
+
+Please shortly describe the bug you have found, and what you expect instead.
+
+## Environment
+
+- Compiler version:
+- Framework/IDE (e.g. Truffle or Remix):
+- EVM execution environment / backend / blockchain client:
+- Operating system:
+
+## Steps to Reproduce
+
+Please provide a *minimal* source code example to trigger the bug you have found.
+Please also mention any command line flags that are necessary for triggering the bug.
+Provide as much information as necessary to reproduce the bug.
+
+```
+// Some *minimal* Solidity source code to reproduce the bug.
+// ...
+```
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..6b98fb99
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,37 @@
+---
+name: Feature Request
+about: Solidity language or infrastructure feature requests.
+---
+
+## Prerequisites
+
+- First, many thanks for taking part in the community. We really appreciate that.
+- We realize there is a lot of data requested here. We ask only that you do your best to provide as much information as possible so we can better help you.
+- Support questions are better asked in one of the following locations:
+ - [Solidity chat](https://gitter.im/ethereum/solidity)
+ - [Stack Overflow](https://ethereum.stackexchange.com/)
+- Ensure the issue isn't already reported (check `feature` and `language design` labels).
+
+*Delete the above section and the instructions in the sections below before submitting*
+
+## Abstract
+
+Please describe by example what problem you see in the current Solidity language
+and reason about it.
+
+## Motivation
+
+In this section you describe how you propose to address the problem you described earlier,
+including by giving one or more exemplary source code snippets for demonstration.
+
+## Specification
+
+The technical specification should describe the syntax and semantics of any new feature. The
+specification should be detailed enough to allow any developer to implement the functionality.
+
+## Backwards Compatibility
+
+All language changes that introduce backwards incompatibilities must include a section describing
+these incompatibilities and their severity.
+
+Please describe how you propose to deal with these incompatibilities.
diff --git a/.github/ISSUE_TEMPLATE/general.md b/.github/ISSUE_TEMPLATE/general.md
new file mode 100644
index 00000000..2d277865
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/general.md
@@ -0,0 +1,19 @@
+---
+name: General Feedback
+about: Any general feedback (neither feature request nor bug reports)
+---
+
+## Prerequisites
+
+- First, many thanks for taking part in the community. We really appreciate that.
+- Read the [contributing guidelines](http://solidity.readthedocs.io/en/latest/contributing.html).
+- Support questions are better asked in one of the following locations:
+ - [Solidity chat](https://gitter.im/ethereum/solidity)
+ - [Stack Overflow](https://ethereum.stackexchange.com/)
+- Ensure the issue isn't already reported.
+
+*Delete the above section and the instructions in the sections below before submitting*
+
+## Description
+
+Please describe the purpose of your ticket.
diff --git a/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 6f544bc1..6f544bc1 100644
--- a/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
diff --git a/Changelog.md b/Changelog.md
index aa2dce18..0790c0ca 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.
@@ -68,6 +69,7 @@ Language Features:
* General: Allow appending ``calldata`` keyword to types, to explicitly specify data location for arguments of external functions.
* General: Support ``pop()`` for storage arrays.
* General: Scoping rules now follow the C99-style.
+ * General: Allow ``enum``s in interfaces.
Compiler Features:
* C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
@@ -78,8 +80,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/cmake/EthOptions.cmake b/cmake/EthOptions.cmake
index b4efd6c9..a79e5135 100644
--- a/cmake/EthOptions.cmake
+++ b/cmake/EthOptions.cmake
@@ -2,7 +2,7 @@ macro(configure_project)
set(NAME ${PROJECT_NAME})
# features
- eth_default_option(PROFILING OFF)
+ eth_default_option(COVERAGE OFF)
# components
eth_default_option(TESTS ON)
@@ -27,7 +27,7 @@ macro(print_config NAME)
message("-- CMAKE_BUILD_TYPE Build type ${CMAKE_BUILD_TYPE}")
message("-- TARGET_PLATFORM Target platform ${CMAKE_SYSTEM_NAME}")
message("--------------------------------------------------------------- features")
- message("-- PROFILING Profiling support ${PROFILING}")
+ message("-- COVERAGE Coverage support ${COVERAGE}")
message("------------------------------------------------------------- components")
if (SUPPORT_TESTS)
message("-- TESTS Build tests ${TESTS}")
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 00000000..f20980ef
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,18 @@
+codecov:
+ branch: develop
+coverage:
+ range: 70...100
+ status:
+ project:
+ default:
+ target: auto
+ paths: "!test/"
+ syntax:
+ target: auto
+ paths: "libsolidity/analysis"
+ flags: syntax
+ tests:
+ target: auto
+ paths: "test/"
+comment:
+ layout: "reach, diff, flags"
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/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp
index 0063a8d4..9693d02a 100644
--- a/libdevcore/CommonIO.cpp
+++ b/libdevcore/CommonIO.cpp
@@ -187,3 +187,23 @@ boost::filesystem::path dev::weaklyCanonicalFilesystemPath(boost::filesystem::pa
return head / tail;
}
}
+
+string dev::absolutePath(string const& _path, string const& _reference)
+{
+ boost::filesystem::path p(_path);
+ // Anything that does not start with `.` is an absolute path.
+ if (p.begin() == p.end() || (*p.begin() != "." && *p.begin() != ".."))
+ return _path;
+ boost::filesystem::path result(_reference);
+ result.remove_filename();
+ for (boost::filesystem::path::iterator it = p.begin(); it != p.end(); ++it)
+ if (*it == "..")
+ result = result.parent_path();
+ else if (*it != ".")
+ result /= *it;
+ return result.generic_string();
+}
+
+string dev::sanitizePath(string const& _path) {
+ return boost::filesystem::path(_path).generic_string();
+}
diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h
index 9ba68e74..928b6d15 100644
--- a/libdevcore/CommonIO.h
+++ b/libdevcore/CommonIO.h
@@ -62,4 +62,10 @@ std::string toString(_T const& _t)
/// Should be replaced by the boost implementation as soon as support for boost<1.60 can be dropped.
boost::filesystem::path weaklyCanonicalFilesystemPath(boost::filesystem::path const &_path);
+/// @returns the absolute path corresponding to @a _path relative to @a _reference.
+std::string absolutePath(std::string const& _path, std::string const& _reference);
+
+/// Helper function to return path converted strings.
+std::string sanitizePath(std::string const& _path);
+
}
diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h
index 7a2bc484..0573856b 100644
--- a/libevmasm/RuleList.h
+++ b/libevmasm/RuleList.h
@@ -46,7 +46,7 @@ template <class S> S modWorkaround(S const& _a, S const& _b)
/// @returns a list of simplification rules given certain match placeholders.
/// A, B and C should represent constants, X and Y arbitrary expressions.
-/// The simplifications should neven change the order of evaluation of
+/// The simplifications should never change the order of evaluation of
/// arbitrary operations.
template <class Pattern>
std::vector<SimplificationRule<Pattern>> simplificationRuleList(
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index ba793933..501521f5 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)
@@ -292,134 +297,138 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
if (_variable.annotation().type)
return;
+ if (!_variable.typeName())
+ {
+ // This can still happen in very unusual cases where a developer uses constructs, such as
+ // `var a;`, however, such code will have generated errors already.
+ // However, we cannot blindingly solAssert() for that here, as the TypeChecker (which is
+ // invoking ReferencesResolver) is generating it, so the error is most likely(!) generated
+ // after this step.
+ return;
+ }
+
TypePointer type;
- if (_variable.typeName())
+ type = _variable.typeName()->annotation().type;
+ using Location = VariableDeclaration::Location;
+ Location varLoc = _variable.referenceLocation();
+ DataLocation typeLoc = DataLocation::Memory;
+ // References are forced to calldata for external function parameters (not return)
+ // and memory for parameters (also return) of publicly visible functions.
+ // They default to memory for function parameters and storage for local variables.
+ // As an exception, "storage" is allowed for library functions.
+ if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
{
- type = _variable.typeName()->annotation().type;
- using Location = VariableDeclaration::Location;
- Location varLoc = _variable.referenceLocation();
- DataLocation typeLoc = DataLocation::Memory;
- // References are forced to calldata for external function parameters (not return)
- // and memory for parameters (also return) of publicly visible functions.
- // They default to memory for function parameters and storage for local variables.
- // As an exception, "storage" is allowed for library functions.
- if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
+ bool isPointer = true;
+ if (_variable.isExternalCallableParameter())
{
- bool isPointer = true;
- if (_variable.isExternalCallableParameter())
+ auto const& contract = dynamic_cast<ContractDefinition const&>(
+ *dynamic_cast<Declaration const&>(*_variable.scope()).scope()
+ );
+ if (contract.isLibrary())
{
- auto const& contract = dynamic_cast<ContractDefinition const&>(
- *dynamic_cast<Declaration const&>(*_variable.scope()).scope()
- );
- if (contract.isLibrary())
- {
- if (varLoc == Location::Memory)
- fatalTypeError(_variable.location(),
- "Location has to be calldata or storage for external "
- "library functions (remove the \"memory\" keyword)."
- );
- }
- else
- {
- // force location of external function parameters (not return) to calldata
- if (varLoc != Location::CallData && varLoc != Location::Default)
- fatalTypeError(_variable.location(),
- "Location has to be calldata for external functions "
- "(remove the \"memory\" or \"storage\" keyword)."
- );
- }
- if (varLoc == Location::Default)
- typeLoc = DataLocation::CallData;
- else
- typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
+ if (varLoc == Location::Memory)
+ fatalTypeError(_variable.location(),
+ "Location has to be calldata or storage for external "
+ "library functions (remove the \"memory\" keyword)."
+ );
}
- else if (_variable.isCallableParameter() && dynamic_cast<Declaration const&>(*_variable.scope()).isPublic())
+ else
{
- auto const& contract = dynamic_cast<ContractDefinition const&>(
- *dynamic_cast<Declaration const&>(*_variable.scope()).scope()
+ // force location of external function parameters (not return) to calldata
+ if (varLoc != Location::CallData && varLoc != Location::Default)
+ fatalTypeError(_variable.location(),
+ "Location has to be calldata for external functions "
+ "(remove the \"memory\" or \"storage\" keyword)."
+ );
+ }
+ if (varLoc == Location::Default)
+ typeLoc = DataLocation::CallData;
+ else
+ typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
+ }
+ else if (_variable.isCallableParameter() && dynamic_cast<Declaration const&>(*_variable.scope()).isPublic())
+ {
+ auto const& contract = dynamic_cast<ContractDefinition const&>(
+ *dynamic_cast<Declaration const&>(*_variable.scope()).scope()
+ );
+ // force locations of public or external function (return) parameters to memory
+ if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary())
+ fatalTypeError(_variable.location(),
+ "Location has to be memory for publicly visible functions "
+ "(remove the \"storage\" or \"calldata\" keyword)."
);
- // force locations of public or external function (return) parameters to memory
- if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary())
+ if (varLoc == Location::Default || !contract.isLibrary())
+ typeLoc = DataLocation::Memory;
+ else
+ {
+ if (varLoc == Location::CallData)
fatalTypeError(_variable.location(),
- "Location has to be memory for publicly visible functions "
- "(remove the \"storage\" or \"calldata\" keyword)."
+ "Location cannot be calldata for non-external functions "
+ "(remove the \"calldata\" keyword)."
);
- if (varLoc == Location::Default || !contract.isLibrary())
+ typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
+ }
+ }
+ else
+ {
+ if (_variable.isConstant())
+ {
+ if (varLoc != Location::Default && varLoc != Location::Memory)
+ fatalTypeError(
+ _variable.location(),
+ "Data location has to be \"memory\" (or unspecified) for constants."
+ );
+ typeLoc = DataLocation::Memory;
+ }
+ else if (varLoc == Location::Default)
+ {
+ if (_variable.isCallableParameter())
typeLoc = DataLocation::Memory;
else
{
- if (varLoc == Location::CallData)
- fatalTypeError(_variable.location(),
- "Location cannot be calldata for non-external functions "
- "(remove the \"calldata\" keyword)."
+ typeLoc = DataLocation::Storage;
+ if (_variable.isLocalVariable())
+ typeError(
+ _variable.location(),
+ "Data location must be specified as either \"memory\" or \"storage\"."
);
- typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
}
}
else
{
- if (_variable.isConstant())
+ switch (varLoc)
{
- if (varLoc != Location::Default && varLoc != Location::Memory)
- fatalTypeError(
- _variable.location(),
- "Data location has to be \"memory\" (or unspecified) for constants."
- );
+ case Location::Memory:
typeLoc = DataLocation::Memory;
+ break;
+ case Location::Storage:
+ typeLoc = DataLocation::Storage;
+ break;
+ case Location::CallData:
+ fatalTypeError(_variable.location(),
+ "Variable cannot be declared as \"calldata\" (remove the \"calldata\" keyword)."
+ );
+ break;
+ default:
+ solAssert(false, "Unknown data location");
}
- else if (varLoc == Location::Default)
- {
- if (_variable.isCallableParameter())
- typeLoc = DataLocation::Memory;
- else
- {
- typeLoc = DataLocation::Storage;
- if (_variable.isLocalVariable())
- typeError(
- _variable.location(),
- "Data location must be specified as either \"memory\" or \"storage\"."
- );
- }
- }
- else
- {
- switch (varLoc)
- {
- case Location::Memory:
- typeLoc = DataLocation::Memory;
- break;
- case Location::Storage:
- typeLoc = DataLocation::Storage;
- break;
- case Location::CallData:
- fatalTypeError(_variable.location(),
- "Variable cannot be declared as \"calldata\" (remove the \"calldata\" keyword)."
- );
- break;
- default:
- solAssert(false, "Unknown data location");
- }
- }
- isPointer = !_variable.isStateVariable();
}
- type = ref->copyForLocation(typeLoc, isPointer);
+ isPointer = !_variable.isStateVariable();
}
- else if (dynamic_cast<MappingType const*>(type.get()))
- {
- if (_variable.isLocalVariable() && varLoc != Location::Storage)
- typeError(
- _variable.location(),
- "Data location for mappings must be specified as \"storage\"."
- );
- }
- else if (varLoc != Location::Default && !ref)
- typeError(_variable.location(), "Data location can only be given for array or struct types.");
-
- _variable.annotation().type = type;
+ type = ref->copyForLocation(typeLoc, isPointer);
}
- else if (!_variable.canHaveAutoType())
- typeError(_variable.location(), "Explicit type needed.");
- // otherwise we have a "var"-declaration whose type is resolved by the first assignment
+ else if (dynamic_cast<MappingType const*>(type.get()))
+ {
+ if (_variable.isLocalVariable() && varLoc != Location::Storage)
+ typeError(
+ _variable.location(),
+ "Data location for mappings must be specified as \"storage\"."
+ );
+ }
+ else if (varLoc != Location::Default && !ref)
+ typeError(_variable.location(), "Data location can only be given for array or struct types.");
+
+ _variable.annotation().type = type;
}
void ReferencesResolver::typeError(SourceLocation const& _location, string const& _description)
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 7cec7c43..38331a43 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -751,13 +751,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
return false;
}
-bool TypeChecker::visit(EnumDefinition const& _enum)
-{
- if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface)
- m_errorReporter.typeError(_enum.location(), "Enumerable cannot be declared in interfaces.");
- return false;
-}
-
void TypeChecker::visitManually(
ModifierInvocation const& _modifier,
vector<ContractDefinition const*> const& _bases
@@ -867,6 +860,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 +868,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 +900,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/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index 47892a3f..b696de85 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -96,7 +96,6 @@ private:
virtual bool visit(StructDefinition const& _struct) override;
virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(VariableDeclaration const& _variable) override;
- virtual bool visit(EnumDefinition const& _enum) override;
/// We need to do this manually because we want to pass the bases of the current contract in
/// case this is a base constructor call.
void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases);
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index 7c3869a8..23797d52 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -466,11 +466,6 @@ bool VariableDeclaration::isExternalCallableParameter() const
return false;
}
-bool VariableDeclaration::canHaveAutoType() const
-{
- return isLocalVariable() && !isCallableParameter();
-}
-
TypePointer VariableDeclaration::type() const
{
return annotation().type;
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index d0d3b1ef..69c6fa05 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -696,7 +696,6 @@ public:
bool isExternalCallableParameter() const;
/// @returns true if the type of the variable does not need to be specified, i.e. it is declared
/// in the body of a function or modifier.
- bool canHaveAutoType() const;
bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; }
bool isConstant() const { return m_isConstant; }
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 7bcae812..3eccc6d4 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -169,15 +169,6 @@ pair<u256, unsigned> const* StorageOffsets::offset(size_t _index) const
return nullptr;
}
-MemberList& MemberList::operator=(MemberList&& _other)
-{
- solAssert(&_other != this, "");
-
- m_memberTypes = move(_other.m_memberTypes);
- m_storageOffsets = move(_other.m_storageOffsets);
- return *this;
-}
-
void MemberList::combine(MemberList const & _other)
{
m_memberTypes += _other.m_memberTypes;
@@ -1146,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/ast/Types.h b/libsolidity/ast/Types.h
index 89b8f170..09323d05 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -95,9 +95,7 @@ public:
using MemberMap = std::vector<Member>;
- MemberList() {}
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
- MemberList& operator=(MemberList&& _other);
void combine(MemberList const& _other);
TypePointer memberType(std::string const& _name) const
{
@@ -132,6 +130,8 @@ private:
mutable std::unique_ptr<StorageOffsets> m_storageOffsets;
};
+static_assert(std::is_nothrow_move_constructible<MemberList>::value, "MemberList should be noexcept move constructible");
+
/**
* Abstract base class that forms the root of the type hierarchy.
*/
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..5cfd1758 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
{
@@ -583,7 +577,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string
for (auto const& node: _ast.nodes())
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
{
- string importPath = absolutePath(import->path(), _sourcePath);
+ string importPath = dev::absolutePath(import->path(), _sourcePath);
// The current value of `path` is the absolute path as seen from this source file.
// We first have to apply remappings before we can store the actual absolute path
// as seen globally.
@@ -626,8 +620,8 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
for (auto const& redir: m_remappings)
{
- string context = sanitizePath(redir.context);
- string prefix = sanitizePath(redir.prefix);
+ string context = dev::sanitizePath(redir.context);
+ string prefix = dev::sanitizePath(redir.prefix);
// Skip if current context is closer
if (context.length() < longestContext)
@@ -644,7 +638,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
longestContext = context.length();
longestPrefix = prefix.length();
- bestMatchTarget = sanitizePath(redir.target);
+ bestMatchTarget = dev::sanitizePath(redir.target);
}
string path = bestMatchTarget;
path.append(_path.begin() + longestPrefix, _path.end());
@@ -681,23 +675,6 @@ void CompilerStack::resolveImports()
swap(m_sourceOrder, sourceOrder);
}
-string CompilerStack::absolutePath(string const& _path, string const& _reference)
-{
- using path = boost::filesystem::path;
- path p(_path);
- // Anything that does not start with `.` is an absolute path.
- if (p.begin() == p.end() || (*p.begin() != "." && *p.begin() != ".."))
- return _path;
- path result(_reference);
- result.remove_filename();
- for (path::iterator it = p.begin(); it != p.end(); ++it)
- if (*it == "..")
- result = result.parent_path();
- else if (*it != ".")
- result /= *it;
- return result.generic_string();
-}
-
namespace
{
bool onlySafeExperimentalFeaturesActivated(set<ExperimentalFeature> const& features)
@@ -767,23 +744,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..2234a8c9 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -36,7 +36,6 @@
#include <json/json.h>
#include <boost/noncopyable.hpp>
-#include <boost/filesystem.hpp>
#include <ostream>
#include <string>
@@ -190,12 +189,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 +251,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;
@@ -274,12 +266,6 @@ private:
std::string applyRemapping(std::string const& _path, std::string const& _context);
void resolveImports();
- /// @returns the absolute path corresponding to @a _path relative to @a _reference.
- static std::string absolutePath(std::string const& _path, std::string const& _reference);
-
- /// Helper function to return path converted strings.
- static std::string sanitizePath(std::string const& _path) { return boost::filesystem::path(_path).generic_string(); }
-
/// @returns true if the contract is requested to be compiled.
bool isRequestedContract(ContractDefinition const& _contract) const;
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index 6dd8fac0..429bd637 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 a8e271d2..7256386d 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..a6c1372b 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -4577,6 +4577,50 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints)
ABI_CHECK(callContractFunction("test()"), encodeArgs(1));
}
+BOOST_AUTO_TEST_CASE(enum_referencing)
+{
+ char const* sourceCode = R"(
+ interface I {
+ enum Direction { A, B, Left, Right }
+ }
+ library L {
+ enum Direction { Left, Right }
+ function f() public pure returns (Direction) {
+ return Direction.Right;
+ }
+ function g() public pure returns (I.Direction) {
+ return I.Direction.Right;
+ }
+ }
+ contract C is I {
+ function f() public pure returns (Direction) {
+ return Direction.Right;
+ }
+ function g() public pure returns (I.Direction) {
+ return I.Direction.Right;
+ }
+ function h() public pure returns (L.Direction) {
+ return L.Direction.Right;
+ }
+ function x() public pure returns (L.Direction) {
+ return L.f();
+ }
+ function y() public pure returns (I.Direction) {
+ return L.g();
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "L");
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(3));
+ compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}});
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("h()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("y()"), encodeArgs(3));
+}
+
BOOST_AUTO_TEST_CASE(inline_member_init)
{
char const* sourceCode = R"(
@@ -12527,6 +12571,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.
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/422_interface_enums.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/422_interface_enums.sol
index 5513817d..1533e7ff 100644
--- a/test/libsolidity/syntaxTests/nameAndTypeResolution/422_interface_enums.sol
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/422_interface_enums.sol
@@ -2,4 +2,3 @@ interface I {
enum A { B, C }
}
// ----
-// TypeError: (18-33): Enumerable cannot be declared in interfaces.
diff --git a/test/libsolidity/syntaxTests/parsing/enum_from_interface.sol b/test/libsolidity/syntaxTests/parsing/enum_from_interface.sol
new file mode 100644
index 00000000..0fe0fbae
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/enum_from_interface.sol
@@ -0,0 +1,9 @@
+interface I {
+ enum Direction { Left, Right }
+}
+
+contract D {
+ function f() public pure returns (I.Direction) {
+ return I.Direction.Left;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/enum_from_interface_in_library.sol b/test/libsolidity/syntaxTests/parsing/enum_from_interface_in_library.sol
new file mode 100644
index 00000000..8d9003eb
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/enum_from_interface_in_library.sol
@@ -0,0 +1,12 @@
+interface I {
+ enum Direction { Left, Right }
+}
+
+library L {
+ function f() public pure returns (I.Direction) {
+ return I.Direction.Left;
+ }
+ function g() internal pure returns (I.Direction) {
+ return I.Direction.Left;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/enum_from_library.sol b/test/libsolidity/syntaxTests/parsing/enum_from_library.sol
new file mode 100644
index 00000000..ab762a82
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/enum_from_library.sol
@@ -0,0 +1,9 @@
+library L {
+ enum Direction { Left, Right }
+}
+
+contract D {
+ function f() public pure returns (L.Direction) {
+ return L.Direction.Left;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/enum_inheritance_contract.sol b/test/libsolidity/syntaxTests/parsing/enum_inheritance_contract.sol
new file mode 100644
index 00000000..e5b98352
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/enum_inheritance_contract.sol
@@ -0,0 +1,9 @@
+contract C {
+ enum Direction { Left, Right }
+}
+
+contract D is C {
+ function f() public pure returns (Direction) {
+ return Direction.Left;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/enum_inheritance_interface.sol b/test/libsolidity/syntaxTests/parsing/enum_inheritance_interface.sol
new file mode 100644
index 00000000..75858744
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/enum_inheritance_interface.sol
@@ -0,0 +1,9 @@
+interface I {
+ enum Direction { Left, Right }
+}
+
+contract D is I {
+ function f() public pure returns (Direction) {
+ return Direction.Left;
+ }
+}