aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--Changelog.md24
-rw-r--r--appveyor.yml5
-rw-r--r--cmake/EthCompilerSettings.cmake12
-rw-r--r--cmake/EthDependencies.cmake2
-rw-r--r--docs/conf.py4
-rw-r--r--docs/index.rst2
-rw-r--r--docs/installing-solidity.rst2
-rw-r--r--docs/solidity-by-example.rst9
-rw-r--r--docs/units-and-global-variables.rst2
-rw-r--r--libdevcore/Exceptions.h26
-rw-r--r--libevmasm/Assembly.cpp6
-rw-r--r--libevmasm/ExpressionClasses.cpp1
-rw-r--r--liblll/CodeFragment.cpp62
-rw-r--r--liblll/CodeFragment.h5
-rw-r--r--liblll/Compiler.cpp7
-rw-r--r--liblll/Parser.cpp17
-rw-r--r--libsolidity/analysis/SemVerHandler.h6
-rw-r--r--libsolidity/analysis/SyntaxChecker.cpp17
-rw-r--r--libsolidity/analysis/TypeChecker.cpp23
-rw-r--r--libsolidity/ast/AST.cpp4
-rw-r--r--libsolidity/ast/AST.h2
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp3
-rw-r--r--libsolidity/ast/Types.cpp29
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp3
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp48
-rw-r--r--libsolidity/codegen/ExpressionCompiler.h2
-rw-r--r--libsolidity/codegen/LValue.cpp8
-rw-r--r--libsolidity/interface/CompilerStack.cpp18
-rw-r--r--lllc/main.cpp16
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp249
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp154
32 files changed, 648 insertions, 122 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index efde0f91..20c96869 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
-set(PROJECT_VERSION "0.4.3")
+set(PROJECT_VERSION "0.4.5")
project(solidity VERSION ${PROJECT_VERSION})
# Let's find our dependencies
diff --git a/Changelog.md b/Changelog.md
index 39e03014..ee106047 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,4 +1,12 @@
-### 0.4.3 (unreleased)
+### 0.4.5 (unreleased)
+
+### 0.4.4 (2016-10-31)
+
+Bugfixes:
+ * Type checker: forbid signed exponential that led to an incorrect use of EXP opcode.
+ * Code generator: properly clean higher order bytes before storing in storage.
+
+### 0.4.3 (2016-10-25)
Features:
@@ -9,13 +17,21 @@ Features:
* Support shifting constant numbers.
Bugfixes:
- * Disallow unknown options in ``solc``.
- * Proper type checking for bound functions.
- * Code Generator: expect zero stack increase after `super` as an expression.
+ * Commandline interface: Disallow unknown options in ``solc``.
+ * Name resolver: Allow inheritance of ``enum`` definitions.
+ * Type checker: Proper type checking for bound functions.
+ * Type checker: fixed crash related to invalid fixed point constants
+ * Type checker: fixed crash related to invalid literal numbers.
+ * Type checker: ``super.x`` does not look up ``x`` in the current contract.
+ * Code generator: expect zero stack increase after ``super`` as an expression.
+ * Code generator: fix an internal compiler error for ``L.Foo`` for ``enum Foo`` defined in library ``L``.
+ * Code generator: allow inheritance of ``enum`` definitions.
* Inline assembly: support the ``address`` opcode.
* Inline assembly: fix parsing of assignment after a label.
* Inline assembly: external variables of unsupported type (such as ``this``, ``super``, etc.)
are properly detected as unusable.
+ * Inline assembly: support variables within modifiers.
+ * Optimizer: fix related to stale knowledge about SHA3 operations
### 0.4.2 (2016-09-17)
diff --git a/appveyor.yml b/appveyor.yml
index b45e9f11..5d6dcb20 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -29,7 +29,7 @@
branches:
only:
- - master
+ - release
- develop
os: Visual Studio 2015
configuration:
@@ -83,14 +83,13 @@ artifacts:
# below.
deploy:
- description: 'Development build of solidity at commit $(APPVEYOR_REPO_COMMIT).\n\n$(APPVEYOR_REPO_COMMIT_MESSAGE)\n\nCommitted by $(APPVEYOR_REPO_COMMIT_AUTHOR), $(APPVEYOR_REPO_COMMIT_TIMESTAMP).'
- prerelease: true
provider: GitHub
auth_token:
secure: HPjiugbDSCsEFTphj/qwHuSw80/BV1xWoSvj95CPmtb16Ukh2VQbLVB7iFtZSans
artifact: solidity-windows-zip
on:
branch: release
+ appveyor_repo_tag: true
notifications:
- provider: GitHubPullRequest
diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake
index 066be4c1..af6ae928 100644
--- a/cmake/EthCompilerSettings.cmake
+++ b/cmake/EthCompilerSettings.cmake
@@ -180,12 +180,12 @@ elseif (DEFINED MSVC)
# Always use Release variant of C++ runtime.
# We don't want to provide Debug variants of all dependencies. Some default
# flags set by CMake must be tweaked.
- string(REPLACE "/MDd" "/MD" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
- string(REPLACE "/D_DEBUG" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
- string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
- string(REPLACE "/MDd" "/MD" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
- string(REPLACE "/D_DEBUG" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
- string(REPLACE "/RTC1" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
+ string(REPLACE "/MDd" "/MD" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ string(REPLACE "/D_DEBUG" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ string(REPLACE "/MDd" "/MD" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+ string(REPLACE "/D_DEBUG" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+ string(REPLACE "/RTC1" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS OFF)
# disable empty object file warning
diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake
index 72585d11..a5e9b0c5 100644
--- a/cmake/EthDependencies.cmake
+++ b/cmake/EthDependencies.cmake
@@ -119,7 +119,7 @@ function(eth_use TARGET REQUIRED)
endif()
foreach(MODULE ${ARGN})
- string(REPLACE "::" ";" MODULE_PARTS ${MODULE})
+ string(REPLACE "::" ";" MODULE_PARTS "${MODULE}")
list(GET MODULE_PARTS 0 MODULE_MAIN)
list(LENGTH MODULE_PARTS MODULE_LENGTH)
if (MODULE_LENGTH GREATER 1)
diff --git a/docs/conf.py b/docs/conf.py
index 4d22c9bd..e17d5fd8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -56,9 +56,9 @@ copyright = '2016, Ethereum'
# built documents.
#
# The short X.Y version.
-version = '0.4.3'
+version = '0.4.5'
# The full version, including alpha/beta/rc tags.
-release = '0.4.3-develop'
+release = '0.4.5-develop'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/index.rst b/docs/index.rst
index 3b47ce78..9bee1515 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -5,7 +5,7 @@ Solidity is a contract-oriented, high-level language whose syntax is similar to
and it is designed to target the Ethereum Virtual Machine.
Solidity is statically typed, supports inheritance, libraries and complex
-user-defines types among other features.
+user-defined types among other features.
As you will see, it is possible to create contracts for voting,
crowdfunding, blind auctions, multi-signature wallets and more.
diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst
index 44ee34f4..ec40e822 100644
--- a/docs/installing-solidity.rst
+++ b/docs/installing-solidity.rst
@@ -12,7 +12,7 @@ Versioning
Solidity versions follow `semantic versioning <https://semver.org>`_ and in addition to
releases, **nightly development builds** are also made available. The nightly builds
are not guaranteed to be working and despite best efforts they might contain undocumented
-and/or broken changes. We recommend to use the latest release. Package installers below
+and/or broken changes. We recommend using the latest release. Package installers below
will use the latest release.
Browser-Solidity
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst
index 2e53b78c..915cfa76 100644
--- a/docs/solidity-by-example.rst
+++ b/docs/solidity-by-example.rst
@@ -170,6 +170,15 @@ of votes.
}
}
}
+
+ // Calls winningProposal() function to get the index
+ // of the winner contained in the proposals array and then
+ // returns the name of the winner
+ function winnerName() constant
+ returns (bytes32 winnerName)
+ {
+ winnerName = proposals[winningProposal()].name;
+ }
}
Possible Improvements
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index 3499bc71..dd3d4be8 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -50,7 +50,7 @@ namespace and are mainly used to provide information about the blockchain.
Block and Transaction Properties
--------------------------------
-- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks
+- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks excluding current
- ``block.coinbase`` (``address``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty
- ``block.gaslimit`` (``uint``): current block gaslimit
diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h
index a6c1f9ab..667ec31c 100644
--- a/libdevcore/Exceptions.h
+++ b/libdevcore/Exceptions.h
@@ -47,41 +47,15 @@ private:
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } }
-/// Base class for all RLP exceptions.
-struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} };
-#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { const char* what() const noexcept override { return #X; } }
-
-DEV_SIMPLE_EXCEPTION_RLP(BadCast);
-DEV_SIMPLE_EXCEPTION_RLP(BadRLP);
-DEV_SIMPLE_EXCEPTION_RLP(OversizeRLP);
-DEV_SIMPLE_EXCEPTION_RLP(UndersizeRLP);
-
DEV_SIMPLE_EXCEPTION(BadHexCharacter);
-DEV_SIMPLE_EXCEPTION(NoNetworking);
-DEV_SIMPLE_EXCEPTION(NoUPnPDevice);
-DEV_SIMPLE_EXCEPTION(RootNotFound);
-struct BadRoot: virtual Exception { public: BadRoot(h256 const& _root): Exception("BadRoot " + _root.hex()), root(_root) {} h256 root; };
DEV_SIMPLE_EXCEPTION(FileError);
-DEV_SIMPLE_EXCEPTION(Overflow);
-DEV_SIMPLE_EXCEPTION(FailedInvariant);
-DEV_SIMPLE_EXCEPTION(ValueTooLarge);
-
-struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} };
-struct ExternalFunctionFailure: virtual Exception { public: ExternalFunctionFailure(std::string _f): Exception("Function " + _f + "() failed.") {} };
// error information to be added to exceptions
using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>;
-using errinfo_wrongAddress = boost::error_info<struct tag_address, std::string>;
using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
using errinfo_required = boost::error_info<struct tag_required, bigint>;
using errinfo_got = boost::error_info<struct tag_got, bigint>;
-using errinfo_min = boost::error_info<struct tag_min, bigint>;
-using errinfo_max = boost::error_info<struct tag_max, bigint>;
-using RequirementError = boost::tuple<errinfo_required, errinfo_got>;
-using errinfo_hash256 = boost::error_info<struct tag_hash, h256>;
using errinfo_required_h256 = boost::error_info<struct tag_required_h256, h256>;
using errinfo_got_h256 = boost::error_info<struct tag_get_h256, h256>;
-using Hash256RequirementError = boost::tuple<errinfo_required_h256, errinfo_got_h256>;
-using errinfo_extraData = boost::error_info<struct tag_extraData, bytes>;
}
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index 450ee6ce..e881c1e2 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -327,8 +327,10 @@ Assembly& Assembly::optimise(bool _enable, bool _isCreation, size_t _runs)
AssemblyItems optimisedItems;
for (BasicBlock const& block: cfg.optimisedBlocks())
{
- assertThrow(!!block.startState, OptimizerException, "");
- CommonSubexpressionEliminator eliminator(*block.startState);
+ // We used to start with the block's initial state but it caused
+ // too many inconsistencies.
+ KnownState emptyState;
+ CommonSubexpressionEliminator eliminator(emptyState);
auto iter = m_items.begin() + block.begin;
auto const end = m_items.begin() + block.end;
while (iter < end)
diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp
index 9d13a57a..cf5e6a0e 100644
--- a/libevmasm/ExpressionClasses.cpp
+++ b/libevmasm/ExpressionClasses.cpp
@@ -257,6 +257,7 @@ Rules::Rules()
{{Instruction::MOD, {0, X}}, [=]{ return u256(0); }},
{{Instruction::AND, {X, 0}}, [=]{ return u256(0); }},
{{Instruction::OR, {X, ~u256(0)}}, [=]{ return ~u256(0); }},
+ {{Instruction::EQ, {X, 0}}, [=]() -> Pattern { return {Instruction::ISZERO, {X}}; } },
// operations involving an expression and itself
{{Instruction::AND, {X, X}}, [=]{ return X; }},
{{Instruction::OR, {X, X}}, [=]{ return X; }},
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index 9dcac845..39b6376c 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -35,9 +35,6 @@
using namespace std;
using namespace dev;
using namespace dev::eth;
-namespace qi = boost::spirit::qi;
-namespace px = boost::phoenix;
-namespace sp = boost::spirit;
void CodeFragment::finalise(CompilerState const& _cs)
{
@@ -90,7 +87,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS
m_asm.append(_s.args.at(s).m_asm);
else if (_s.outers.count(s))
m_asm.append(_s.outers.at(s).m_asm);
- else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos)
+ else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_-") == string::npos)
{
auto it = _s.vars.find(s);
if (it == _s.vars.end())
@@ -330,9 +327,32 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
if (nonStandard)
return;
- std::map<std::string, Instruction> const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD }, { "&", Instruction::AND }, { "|", Instruction::OR }, { "^", Instruction::XOR } };
- std::map<std::string, pair<Instruction, bool>> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "S<", { Instruction::SLT, false } }, { "S<=", { Instruction::SGT, true } }, { "S>", { Instruction::SGT, false } }, { "S>=", { Instruction::SLT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } };
- std::map<std::string, Instruction> const c_unary = { { "!", Instruction::ISZERO } };
+ std::map<std::string, Instruction> const c_arith = {
+ { "+", Instruction::ADD },
+ { "-", Instruction::SUB },
+ { "*", Instruction::MUL },
+ { "/", Instruction::DIV },
+ { "%", Instruction::MOD },
+ { "&", Instruction::AND },
+ { "|", Instruction::OR },
+ { "^", Instruction::XOR }
+ };
+ std::map<std::string, pair<Instruction, bool>> const c_binary = {
+ { "<", { Instruction::LT, false } },
+ { "<=", { Instruction::GT, true } },
+ { ">", { Instruction::GT, false } },
+ { ">=", { Instruction::LT, true } },
+ { "S<", { Instruction::SLT, false } },
+ { "S<=", { Instruction::SGT, true } },
+ { "S>", { Instruction::SGT, false } },
+ { "S>=", { Instruction::SLT, true } },
+ { "=", { Instruction::EQ, false } },
+ { "!=", { Instruction::EQ, true } }
+ };
+ std::map<std::string, Instruction> const c_unary = {
+ { "!", Instruction::ISZERO },
+ { "~", Instruction::NOT }
+ };
vector<CodeFragment> code;
CompilerState ns = _s;
@@ -449,14 +469,15 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm << end.tag();
m_asm.donePaths();
}
- else if (us == "WHILE")
+ else if (us == "WHILE" || us == "UNTIL")
{
requireSize(2);
requireDeposit(0, 1);
auto begin = m_asm.append();
m_asm.append(code[0].m_asm);
- m_asm.append(Instruction::ISZERO);
+ if (us == "WHILE")
+ m_asm.append(Instruction::ISZERO);
auto end = m_asm.appendJumpI();
m_asm.append(code[1].m_asm, 0);
m_asm.appendJump(begin);
@@ -541,17 +562,6 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
// At end now.
m_asm.append(end);
}
- else if (us == "~")
- {
- requireSize(1);
- requireDeposit(0, 1);
-
- m_asm.append(code[0].m_asm, 1);
- m_asm.append((u256)1);
- m_asm.append((u256)0);
- m_asm.append(Instruction::SUB);
- m_asm.append(Instruction::SUB);
- }
else if (us == "SEQ")
{
unsigned ii = 0;
@@ -567,10 +577,18 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm.append(i.m_asm);
m_asm.popTo(1);
}
- else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos)
+ else if (us == "PANIC")
+ {
+ m_asm.appendJump(m_asm.errorTag());
+ }
+ else if (us == "BYTECODESIZE")
+ {
+ m_asm.appendProgramSize();
+ }
+ else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_-") == string::npos)
m_asm.append((u256)varAddress(s));
else
- error<InvalidOperation>();
+ error<InvalidOperation>("Unsupported keyword: '" + us + "'");
}
}
diff --git a/liblll/CodeFragment.h b/liblll/CodeFragment.h
index e0d48ab7..637d169f 100644
--- a/liblll/CodeFragment.h
+++ b/liblll/CodeFragment.h
@@ -51,6 +51,11 @@ private:
void finalise(CompilerState const& _cs);
template <class T> void error() const { BOOST_THROW_EXCEPTION(T() ); }
+ template <class T> void error(std::string const& reason) const {
+ auto err = T();
+ err << errinfo_comment(reason);
+ BOOST_THROW_EXCEPTION(err);
+ }
void constructOperation(sp::utree const& _t, CompilerState& _s);
bool m_finalised = false;
diff --git a/liblll/Compiler.cpp b/liblll/Compiler.cpp
index 68499106..4008022f 100644
--- a/liblll/Compiler.cpp
+++ b/liblll/Compiler.cpp
@@ -34,8 +34,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
{
CompilerState cs;
cs.populateStandard();
- auto f = CodeFragment::compile(_src, cs);
- bytes ret = f.assembly(cs).optimise(_opt).assemble().bytecode;
+ bytes ret = CodeFragment::compile(_src, cs).assembly(cs).optimise(_opt).assemble().bytecode;
for (auto i: cs.treesToKill)
killBigints(i);
return ret;
@@ -59,7 +58,7 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
catch (...)
{
if (_errors)
- _errors->push_back("Internal parse exception.");
+ _errors->push_back("Internal compiler exception.");
}
return bytes();
}
@@ -93,7 +92,7 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v
catch (...)
{
if (_errors)
- _errors->push_back("Internal parse exception.");
+ _errors->push_back("Internal compiler exception.");
}
return string();
}
diff --git a/liblll/Parser.cpp b/liblll/Parser.cpp
index 2754e9f5..219d4f54 100644
--- a/liblll/Parser.cpp
+++ b/liblll/Parser.cpp
@@ -101,8 +101,8 @@ void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out)
qi::rule<it, string()> strsh = '\'' > qi::lexeme[+(~qi::char_(std::string(" ;$@()[]{}:\n\t") + '\0'))];
qi::rule<it, symbol_type()> symbol = qi::lexeme[+(~qi::char_(std::string(" $@[]{}:();\"\x01-\x1f\x7f") + '\0'))];
qi::rule<it, string()> intstr = qi::lexeme[ qi::no_case["0x"][qi::_val = "0x"] >> *qi::char_("0-9a-fA-F")[qi::_val += qi::_1]] | qi::lexeme[+qi::char_("0-9")[qi::_val += qi::_1]];
- qi::rule<it, bigint()> integer = intstr;
- qi::rule<it, space_type, sp::utree()> atom = integer[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
+ qi::rule<it, sp::utree()> integer = intstr[qi::_val = px::construct<sp::any_ptr>(px::new_<bigint>(qi::_1))];
+ qi::rule<it, space_type, sp::utree()> atom = integer[qi::_val = qi::_1] | (str | strsh)[qi::_val = qi::_1] | symbol[qi::_val = qi::_1];
qi::rule<it, space_type, sp::utree::list_type()> seq = '{' > *element > '}';
qi::rule<it, space_type, sp::utree::list_type()> mload = '@' > element;
qi::rule<it, space_type, sp::utree::list_type()> sload = qi::lit("@@") > element;
@@ -135,10 +135,19 @@ void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out)
s.push_back(i);
}
auto ret = s.cbegin();
- qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out);
+ try
+ {
+ qi::phrase_parse(ret, s.cend(), element, space, qi::skip_flag::dont_postskip, o_out);
+ }
+ catch (qi::expectation_failure<it> const& e)
+ {
+ std::string fragment(e.first, e.last);
+ std::string loc = std::to_string(std::distance(s.cbegin(), e.first) - 1);
+ std::string reason("Lexer failure at " + loc + ": '" + fragment + "'");
+ BOOST_THROW_EXCEPTION(ParserException() << errinfo_comment(reason));
+ }
for (auto i = ret; i != s.cend(); ++i)
if (!isspace(*i)) {
BOOST_THROW_EXCEPTION(ParserException() << errinfo_comment("Non-whitespace left in parser"));
}
}
-
diff --git a/libsolidity/analysis/SemVerHandler.h b/libsolidity/analysis/SemVerHandler.h
index 3c110b19..e3b642db 100644
--- a/libsolidity/analysis/SemVerHandler.h
+++ b/libsolidity/analysis/SemVerHandler.h
@@ -40,6 +40,12 @@ struct SemVerVersion
std::string prerelease;
std::string build;
+ unsigned major() const { return numbers[0]; }
+ unsigned minor() const { return numbers[1]; }
+ unsigned patch() const { return numbers[2]; }
+
+ bool isPrerelease() const { return !prerelease.empty(); }
+
explicit SemVerVersion(std::string const& _versionString = "0.0.0");
};
diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp
index dc8c1806..dbaa15ed 100644
--- a/libsolidity/analysis/SyntaxChecker.cpp
+++ b/libsolidity/analysis/SyntaxChecker.cpp
@@ -52,13 +52,22 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit)
{
if (!m_versionPragmaFound)
{
+ string errorString("Source file does not specify required compiler version!");
+ SemVerVersion recommendedVersion{string(VersionString)};
+ if (!recommendedVersion.isPrerelease())
+ errorString +=
+ "Consider adding \"pragma solidity ^" +
+ to_string(recommendedVersion.major()) +
+ string(".") +
+ to_string(recommendedVersion.minor()) +
+ string(".") +
+ to_string(recommendedVersion.patch());
+ string(";\"");
+
auto err = make_shared<Error>(Error::Type::Warning);
*err <<
errinfo_sourceLocation(_sourceUnit.location()) <<
- errinfo_comment(
- string("Source file does not specify required compiler version! ") +
- string("Consider adding \"pragma solidity ^") + VersionNumber + string(";\".")
- );
+ errinfo_comment(errorString);
m_errors.push_back(err);
}
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index b5955c8f..46f4f7f6 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -880,6 +880,10 @@ bool TypeChecker::visit(Conditional const& _conditional)
TypePointer trueType = type(_conditional.trueExpression())->mobileType();
TypePointer falseType = type(_conditional.falseExpression())->mobileType();
+ if (!trueType)
+ fatalTypeError(_conditional.trueExpression().location(), "Invalid mobile type.");
+ if (!falseType)
+ fatalTypeError(_conditional.falseExpression().location(), "Invalid mobile type.");
TypePointer commonType = Type::commonType(trueType, falseType);
if (!commonType)
@@ -986,10 +990,16 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
types.push_back(type(*components[i]));
if (_tuple.isInlineArray())
solAssert(!!types[i], "Inline array cannot have empty components");
- if (i == 0 && _tuple.isInlineArray())
- inlineArrayType = types[i]->mobileType();
- else if (_tuple.isInlineArray() && inlineArrayType)
- inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType());
+ if (_tuple.isInlineArray())
+ {
+ if ((i == 0 || inlineArrayType) && !types[i]->mobileType())
+ fatalTypeError(components[i]->location(), "Invalid mobile type.");
+
+ if (i == 0)
+ inlineArrayType = types[i]->mobileType();
+ else if (inlineArrayType)
+ inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType());
+ }
}
else
types.push_back(TypePointer());
@@ -1376,6 +1386,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
}
else if (exprType->category() == Type::Category::FixedBytes)
annotation.isLValue = false;
+ else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType.get()))
+ {
+ if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType().get()))
+ annotation.isLValue = annotation.referencedDeclaration->isLValue();
+ }
return false;
}
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index cca19a4e..695d9881 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -189,6 +189,7 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
m_inheritableMembers.reset(new vector<Declaration const*>());
auto addInheritableMember = [&](Declaration const* _decl)
{
+ solAssert(_decl, "addInheritableMember got a nullpointer.");
if (memberSeen.count(_decl->name()) == 0 && _decl->isVisibleInDerivedContracts())
{
memberSeen.insert(_decl->name());
@@ -204,6 +205,9 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
for (StructDefinition const* s: definedStructs())
addInheritableMember(s);
+
+ for (EnumDefinition const* e: definedEnums())
+ addInheritableMember(e);
}
return *m_inheritableMembers;
}
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 8fd1584d..7ed4ddce 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -623,7 +623,7 @@ public:
virtual bool isLValue() const override;
virtual bool isPartOfExternalInterface() const override { return isPublic(); }
- bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(scope()); }
+ bool isLocalVariable() const { return !!dynamic_cast<CallableDeclaration const*>(scope()); }
/// @returns true if this variable is a parameter or return parameter of a function.
bool isCallableParameter() const;
/// @returns true if this variable is a parameter (not return parameter) of an external function.
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index 0ea5e093..b573feda 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -174,7 +174,8 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
addJsonNode(_node, "FunctionDefinition", {
make_pair("name", _node.name()),
make_pair("public", _node.isPublic()),
- make_pair("constant", _node.isDeclaredConst())
+ make_pair("constant", _node.isDeclaredConst()),
+ make_pair("payable", _node.isPayable())
}, true);
return true;
}
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index eb98047c..7fe97fa7 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -23,6 +23,7 @@
#include <libsolidity/ast/Types.h>
#include <limits>
#include <boost/range/adaptor/reversed.hpp>
+#include <boost/range/adaptor/sliced.hpp>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/SHA3.h>
@@ -197,7 +198,9 @@ TypePointer Type::forLiteral(Literal const& _literal)
TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
{
- if (_b->isImplicitlyConvertibleTo(*_a))
+ if (!_a || !_b)
+ return TypePointer();
+ else if (_b->isImplicitlyConvertibleTo(*_a))
return _a;
else if (_a->isImplicitlyConvertibleTo(*_b))
return _b;
@@ -346,11 +349,14 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
return commonType;
if (Token::isBooleanOp(_operator))
return TypePointer();
- // Nothing else can be done with addresses
if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType))
{
+ // Nothing else can be done with addresses
if (intType->isAddress())
return TypePointer();
+ // Signed EXP is not allowed
+ if (Token::Exp == _operator && intType->isSigned())
+ return TypePointer();
}
else if (auto fixType = dynamic_pointer_cast<FixedPointType const>(commonType))
if (Token::Exp == _operator)
@@ -482,7 +488,7 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
!all_of(radixPoint + 1, _literal.value().end(), ::isdigit) ||
!all_of(_literal.value().begin(), radixPoint, ::isdigit)
)
- throw;
+ return make_tuple(false, rational(0));
//Only decimal notation allowed here, leading zeros would switch to octal.
auto fractionalBegin = find_if_not(
radixPoint + 1,
@@ -1324,7 +1330,10 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) con
if (m_super)
{
// add the most derived of all functions which are visible in derived contracts
- for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts)
+ auto bases = m_contract.annotation().linearizedBaseContracts;
+ solAssert(bases.size() >= 1, "linearizedBaseContracts should at least contain the most derived contract.");
+ // `sliced(1, ...)` ignores the most derived contract, which should not be searchable from `super`.
+ for (ContractDefinition const* base: bases | boost::adaptors::sliced(1, bases.size()))
for (FunctionDefinition const* function: base->definedFunctions())
{
if (!function->isVisibleInDerivedContracts())
@@ -1657,7 +1666,17 @@ TypePointer TupleType::mobileType() const
{
TypePointers mobiles;
for (auto const& c: components())
- mobiles.push_back(c ? c->mobileType() : TypePointer());
+ {
+ if (c)
+ {
+ auto mt = c->mobileType();
+ if (!mt)
+ return TypePointer();
+ mobiles.push_back(mt);
+ }
+ else
+ mobiles.push_back(TypePointer());
+ }
return make_shared<TupleType>(mobiles);
}
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index ec496df8..e064c1a6 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -368,8 +368,11 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << Instruction::MUL;
}
else if (targetTypeCategory == Type::Category::Enum)
+ {
+ solAssert(_typeOnStack.mobileType(), "");
// just clean
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
+ }
else if (targetTypeCategory == Type::Category::FixedPoint)
{
solAssert(
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 3d05edd3..9a096e2d 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -56,8 +56,10 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
if (_varDecl.annotation().type->dataStoredIn(DataLocation::Storage))
{
// reference type, only convert value to mobile type and do final conversion in storeValue.
- utils().convertType(*type, *type->mobileType());
- type = type->mobileType();
+ auto mt = type->mobileType();
+ solAssert(mt, "");
+ utils().convertType(*type, *mt);
+ type = mt;
}
else
{
@@ -861,11 +863,12 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
}
// Special processing for TypeType because we do not want to visit the library itself
- // for internal functions.
+ // for internal functions, or enum/struct definitions.
if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type.get()))
{
if (dynamic_cast<ContractType const*>(type->actualType().get()))
{
+ solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
{
if (funType->location() != FunctionType::Location::Internal)
@@ -883,6 +886,12 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
m_context << m_context.functionEntryLabel(*function).pushTag();
}
}
+ else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type.get()))
+ {
+ // no-op
+ }
+ else if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
+ appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
else
_memberAccess.expression().accept(*this);
}
@@ -1196,15 +1205,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
m_context << m_context.virtualFunctionEntryLabel(*functionDef).pushTag();
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
- {
- if (!variable->isConstant())
- setLValueFromDeclaration(*declaration, _identifier);
- else
- {
- variable->value()->accept(*this);
- utils().convertType(*variable->value()->annotation().type, *variable->annotation().type);
- }
- }
+ appendVariable(*variable, static_cast<Expression const&>(_identifier));
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
{
if (contract->isLibrary())
@@ -1432,11 +1433,17 @@ void ExpressionCompiler::appendExternalFunctionCall(
// Evaluate arguments.
TypePointers argumentTypes;
TypePointers parameterTypes = _functionType.parameterTypes();
- bool manualFunctionId =
+ bool manualFunctionId = false;
+ if (
(funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode || funKind == FunctionKind::BareDelegateCall) &&
- !_arguments.empty() &&
- _arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) ==
+ !_arguments.empty()
+ )
+ {
+ solAssert(_arguments.front()->annotation().type->mobileType(), "");
+ manualFunctionId =
+ _arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) ==
CompilerUtils::dataStartOffset;
+ }
if (manualFunctionId)
{
// If we have a Bare* and the first type has exactly 4 bytes, use it as
@@ -1633,6 +1640,17 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
utils().storeInMemoryDynamic(_expectedType);
}
+void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression)
+{
+ if (!_variable.isConstant())
+ setLValueFromDeclaration(_variable, _expression);
+ else
+ {
+ _variable.value()->accept(*this);
+ utils().convertType(*_variable.value()->annotation().type, *_variable.annotation().type);
+ }
+}
+
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
{
if (m_context.isLocalVariable(&_declaration))
diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h
index 43a92a10..f4ce1fec 100644
--- a/libsolidity/codegen/ExpressionCompiler.h
+++ b/libsolidity/codegen/ExpressionCompiler.h
@@ -103,6 +103,8 @@ private:
/// expected to be on the stack and is updated by this call.
void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression);
+ /// Appends code for a variable that might be a constant or not
+ void appendVariable(VariableDeclaration const& _variable, Expression const& _expression);
/// Sets the current LValue to a new one (of the appropriate type) from the given declaration.
/// Also retrieves the value if it was not requested by @a _expression.
void setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression);
diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp
index 553e5518..c1e05792 100644
--- a/libsolidity/codegen/LValue.cpp
+++ b/libsolidity/codegen/LValue.cpp
@@ -231,10 +231,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
m_context
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes()))
<< Instruction::SWAP1 << Instruction::DIV;
- else if (
- m_dataType->category() == Type::Category::Integer &&
- dynamic_cast<IntegerType const&>(*m_dataType).isSigned()
- )
+ else
// remove the higher order bits
m_context
<< (u256(1) << (8 * (32 - m_dataType->storageBytes())))
@@ -242,9 +239,6 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
<< Instruction::DUP2
<< Instruction::MUL
<< Instruction::DIV;
- else if (m_dataType->category() == Type::Category::FixedPoint)
- // implementation should be very similar to the integer case.
- solAssert(false, "Not yet implemented - FixedPointType.");
m_context << Instruction::MUL << Instruction::OR;
// stack: value storage_ref updated_value
m_context << Instruction::SWAP1 << Instruction::SSTORE;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 476721db..efbbd237 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -21,8 +21,10 @@
* Full-stack compiler that converts a source code string to bytecode.
*/
-#include <boost/algorithm/string.hpp>
-#include <boost/filesystem.hpp>
+#include <libsolidity/interface/CompilerStack.h>
+
+#include <libsolidity/interface/Version.h>
+#include <libsolidity/analysis/SemVerHandler.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h>
@@ -32,12 +34,15 @@
#include <libsolidity/analysis/DocStringAnalyser.h>
#include <libsolidity/analysis/SyntaxChecker.h>
#include <libsolidity/codegen/Compiler.h>
-#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/InterfaceHandler.h>
#include <libsolidity/formal/Why3Translator.h>
#include <libdevcore/SHA3.h>
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+
+
using namespace std;
using namespace dev;
using namespace dev::solidity;
@@ -100,6 +105,13 @@ bool CompilerStack::parse()
m_errors.clear();
m_parseSuccessful = false;
+ if (SemVerVersion{string(VersionString)}.isPrerelease())
+ {
+ auto err = make_shared<Error>(Error::Type::Warning);
+ *err << errinfo_comment("This is a pre-release compiler version, please do not use it in production.");
+ m_errors.push_back(err);
+ }
+
vector<string> sourcesToParse;
for (auto const& s: m_sources)
sourcesToParse.push_back(s.first);
diff --git a/lllc/main.cpp b/lllc/main.cpp
index 06611af0..9763e820 100644
--- a/lllc/main.cpp
+++ b/lllc/main.cpp
@@ -27,11 +27,18 @@
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libevmasm/Instruction.h>
+#include <solidity/BuildInfo.h>
+
using namespace std;
using namespace dev;
using namespace dev::solidity;
using namespace dev::eth;
+static string const VersionString =
+ string(ETH_PROJECT_VERSION) +
+ (string(SOL_VERSION_PRERELEASE).empty() ? "" : "-" + string(SOL_VERSION_PRERELEASE)) +
+ (string(SOL_VERSION_BUILDINFO).empty() ? "" : "+" + string(SOL_VERSION_BUILDINFO));
+
void help()
{
cout
@@ -41,6 +48,7 @@ void help()
<< " -x,--hex Parse, compile and assemble; output byte code in hex." << endl
<< " -a,--assembly Only parse and compile; show assembly." << endl
<< " -t,--parse-tree Only parse; show parse tree." << endl
+ << " -o,--optimise Turn on/off the optimiser; off by default." << endl
<< " -h,--help Show this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl;
exit(0);
@@ -49,7 +57,7 @@ void help()
void version()
{
cout << "LLLC, the Lovely Little Language Compiler " << endl;
- cout << " By Gav Wood, (c) 2014." << endl;
+ cout << "Version: " << VersionString << endl;
exit(0);
}
@@ -81,7 +89,7 @@ enum Mode { Binary, Hex, Assembly, ParseTree, Disassemble };
int main(int argc, char** argv)
{
setDefaultOrCLocale();
- unsigned optimise = 1;
+ unsigned optimise = 0;
string infile;
Mode mode = Hex;
@@ -98,8 +106,8 @@ int main(int argc, char** argv)
mode = Assembly;
else if (arg == "-t" || arg == "--parse-tree")
mode = ParseTree;
- else if ((arg == "-o" || arg == "--optimise") && argc > i + 1)
- optimise = atoi(argv[++i]);
+ else if (arg == "-o" || arg == "--optimise")
+ optimise = 1;
else if (arg == "-d" || arg == "--disassemble")
mode = Disassemble;
else if (arg == "-V" || arg == "--version")
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 088fe4d1..8600443d 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -3314,6 +3314,57 @@ BOOST_AUTO_TEST_CASE(using_enums)
BOOST_CHECK(callContractFunction("getChoice()") == encodeArgs(2));
}
+BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name)
+{
+ char const* sourceCode = R"(
+ contract test {
+ enum Choice { A, B, C }
+ function answer () returns (test.Choice _ret)
+ {
+ _ret = test.Choice.B;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("answer()") == encodeArgs(1));
+}
+
+BOOST_AUTO_TEST_CASE(using_inherited_enum)
+{
+ char const* sourceCode = R"(
+ contract base {
+ enum Choice { A, B, C }
+ }
+
+ contract test is base {
+ function answer () returns (Choice _ret)
+ {
+ _ret = Choice.B;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("answer()") == encodeArgs(1));
+}
+
+BOOST_AUTO_TEST_CASE(using_inherited_enum_excplicitly)
+{
+ char const* sourceCode = R"(
+ contract base {
+ enum Choice { A, B, C }
+ }
+
+ contract test is base {
+ function answer () returns (base.Choice _ret)
+ {
+ _ret = base.Choice.B;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("answer()") == encodeArgs(1));
+}
+
BOOST_AUTO_TEST_CASE(constructing_enums_from_ints)
{
char const* sourceCode = R"(
@@ -5615,6 +5666,120 @@ BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable)
BOOST_CHECK(callContractFunction("ticketPrice()") == encodeArgs(u256(555)));
}
+BOOST_AUTO_TEST_CASE(state_variable_under_contract_name)
+{
+ char const* text = R"(
+ contract Scope {
+ uint stateVar = 42;
+
+ function getStateVar() constant returns (uint stateVar) {
+ stateVar = Scope.stateVar;
+ }
+ }
+ )";
+ compileAndRun(text);
+ BOOST_CHECK(callContractFunction("getStateVar()") == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(state_variable_local_variable_mixture)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint x = 1;
+ uint y = 2;
+ function a() returns (uint x) {
+ x = A.y;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(inherited_function) {
+ char const* sourceCode = R"(
+ contract A { function f() internal returns (uint) { return 1; } }
+ contract B is A {
+ function f() internal returns (uint) { return 2; }
+ function g() returns (uint) {
+ return A.f();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "B");
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(inherited_function_from_a_library) {
+ char const* sourceCode = R"(
+ library A { function f() internal returns (uint) { return 1; } }
+ contract B {
+ function f() internal returns (uint) { return 2; }
+ function g() returns (uint) {
+ return A.f();
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "B");
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(inherited_constant_state_var)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint constant x = 7;
+ }
+ contract B is A {
+ function f() returns (uint) {
+ return A.x;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "B");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(multiple_inherited_state_vars)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint x = 7;
+ }
+ contract B {
+ uint x = 9;
+ }
+ contract C is A, B {
+ function a() returns (uint) {
+ return A.x;
+ }
+ function b() returns (uint) {
+ return B.x;
+ }
+ function a_set(uint _x) returns (uint) {
+ A.x = _x;
+ return 1;
+ }
+ function b_set(uint _x) returns (uint) {
+ B.x = _x;
+ return 1;
+ }
+ }
+ )";
+
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(7)));
+ BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(9)));
+ BOOST_CHECK(callContractFunction("a_set(uint256)", u256(1)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("b_set(uint256)", u256(3)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(3)));
+}
+
BOOST_AUTO_TEST_CASE(constant_string_literal)
{
char const* sourceCode = R"(
@@ -5854,6 +6019,48 @@ BOOST_AUTO_TEST_CASE(using_library_structs)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7), u256(8)));
}
+BOOST_AUTO_TEST_CASE(library_struct_as_an_expression)
+{
+ char const* sourceCode = R"(
+ library Arst {
+ struct Foo {
+ int Things;
+ int Stuff;
+ }
+ }
+
+ contract Tsra {
+ function f() returns(uint) {
+ Arst.Foo;
+ return 1;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "Tsra");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(library_enum_as_an_expression)
+{
+ char const* sourceCode = R"(
+ library Arst {
+ enum Foo {
+ Things,
+ Stuff
+ }
+ }
+
+ contract Tsra {
+ function f() returns(uint) {
+ Arst.Foo;
+ return 1;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "Tsra");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
+}
+
BOOST_AUTO_TEST_CASE(short_strings)
{
// This test verifies that the byte array encoding that combines length and data works
@@ -7304,6 +7511,48 @@ BOOST_AUTO_TEST_CASE(shift_negative_constant_right)
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(-0x42)));
}
+BOOST_AUTO_TEST_CASE(inline_assembly_in_modifiers)
+{
+ char const* sourceCode = R"(
+ contract C {
+ modifier m {
+ uint a = 1;
+ assembly {
+ a := 2
+ }
+ if (a != 2)
+ throw;
+ _;
+ }
+ function f() m returns (bool) {
+ return true;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(true));
+}
+
+BOOST_AUTO_TEST_CASE(packed_storage_overflow)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint16 x = 0x1234;
+ uint16 a = 0xffff;
+ uint16 b;
+ function f() returns (uint, uint, uint, uint) {
+ a++;
+ uint c = b;
+ delete b;
+ a -= 2;
+ return (x, c, b, a);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe)));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 83472369..640cc108 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -854,6 +854,23 @@ BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(super_excludes_current_contract)
+{
+ char const* text = R"(
+ contract A {
+ function b() {}
+ }
+
+ contract B is A {
+ function f() {
+ super.f();
+ }
+ }
+ )";
+
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(function_modifier_invocation)
{
char const* text = R"(
@@ -1019,6 +1036,19 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist");
}
+BOOST_AUTO_TEST_CASE(missing_state_variable)
+{
+ char const* text = R"(
+ contract Scope {
+ function getStateVar() constant returns (uint stateVar) {
+ stateVar = Scope.stateVar; // should fail.
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+
BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
{
// test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126
@@ -1439,6 +1469,21 @@ BOOST_AUTO_TEST_CASE(enum_invalid_member_access)
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(enum_invalid_direct_member_access)
+{
+ char const* text = R"(
+ contract test {
+ enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
+ function test()
+ {
+ choices = Sit;
+ }
+ ActionChoices choices;
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::DeclarationError);
+}
+
BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay)
{
char const* text = R"(
@@ -1500,6 +1545,23 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values)
BOOST_CHECK(expectError(text) == Error::Type::DeclarationError);
}
+BOOST_AUTO_TEST_CASE(enum_name_resolution_under_current_contract_name)
+{
+ char const* text = R"(
+ contract A {
+ enum Foo {
+ First,
+ Second
+ }
+
+ function a() {
+ A.Foo;
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
BOOST_AUTO_TEST_CASE(private_visibility)
{
char const* sourceCode = R"(
@@ -2036,6 +2098,22 @@ BOOST_AUTO_TEST_CASE(integer_boolean_operators)
BOOST_CHECK(expectError(sourceCode3) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(exp_signed_variable)
+{
+ char const* sourceCode1 = R"(
+ contract test { function() { uint x = 3; int y = -4; x ** y; } }
+ )";
+ BOOST_CHECK(expectError(sourceCode1) == Error::Type::TypeError);
+ char const* sourceCode2 = R"(
+ contract test { function() { uint x = 3; int y = -4; y ** x; } }
+ )";
+ BOOST_CHECK(expectError(sourceCode2) == Error::Type::TypeError);
+ char const* sourceCode3 = R"(
+ contract test { function() { int x = -3; int y = -4; x ** y; } }
+ )";
+ BOOST_CHECK(expectError(sourceCode3) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(reference_compare_operators)
{
char const* sourceCode1 = R"(
@@ -4039,6 +4117,18 @@ BOOST_AUTO_TEST_CASE(using_directive_for_missing_selftype)
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
+{
+ char const* text = R"(
+ contract A {
+ function a() {
+ .8E0;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(shift_constant_left_negative_rvalue)
{
char const* text = R"(
@@ -4107,6 +4197,70 @@ BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_negative_stack)
BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
}
+BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier)
+{
+ char const* text = R"(
+ contract test {
+ modifier m {
+ uint a = 1;
+ assembly {
+ a := 2
+ }
+ _;
+ }
+ function f() m {
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_storage)
+{
+ char const* text = R"(
+ contract test {
+ uint x = 1;
+ function f() {
+ assembly {
+ x := 2
+ }
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::DeclarationError);
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers)
+{
+ char const* text = R"(
+ contract test {
+ uint x = 1;
+ modifier m {
+ assembly {
+ x := 2
+ }
+ _;
+ }
+ function f() m {
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::DeclarationError);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_mobile_type)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ // Invalid number
+ [1, 78901234567890123456789012345678901234567890123456789345678901234567890012345678012345678901234567];
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}