aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md2
-rw-r--r--docs/assembly.rst6
-rw-r--r--libsolidity/analysis/TypeChecker.cpp5
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp13
-rw-r--r--test/libsolidity/InlineAssembly.cpp12
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp15
6 files changed, 45 insertions, 8 deletions
diff --git a/Changelog.md b/Changelog.md
index 83134ee7..eed7e258 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -9,7 +9,9 @@ Features:
* Inline Assembly: introduce ``keccak256`` as an opcode. ``sha3`` is still a valid alias.
Bugfixes:
+ * Fixed crash concerning non-callable types.
* Unused variable warnings no longer issued for variables used inside inline assembly.
+ * Inline Assembly: Enforce function arguments when parsing functional instructions.
### 0.4.11 (2017-05-03)
diff --git a/docs/assembly.rst b/docs/assembly.rst
index 938b72fa..394fc9f5 100644
--- a/docs/assembly.rst
+++ b/docs/assembly.rst
@@ -325,8 +325,10 @@ would be written as follows
mstore(0x80, add(mload(0x80), 3))
-Functional style and instructional style can be mixed, but any opcode inside a
-functional style expression has to return exactly one stack slot (most of the opcodes do).
+Functional style expressions cannot use instructional style internally, i.e.
+``1 2 mstore(0x80, add)`` is not valid assembly, it has to be written as
+``mstore(0x80, add(2, 1))``. For opcodes that do not take arguments, the
+parentheses can be omitted.
Note that the order of arguments is reversed in functional-style as opposed to the instruction-style
way. If you use functional-style, the first argument will end up on the stack top.
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index b1911ef0..2a8d1ff6 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1287,14 +1287,11 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
membersRemovedForStructConstructor = structType.membersMissingInMemory();
_functionCall.annotation().isPure = isPure;
}
- else
- {
- functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
+ else if ((functionType = dynamic_pointer_cast<FunctionType const>(expressionType)))
_functionCall.annotation().isPure =
isPure &&
_functionCall.expression().annotation().isPure &&
functionType->isPure();
- }
if (!functionType)
{
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index 68a9cb03..f9b073ba 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -174,6 +174,19 @@ assembly::Case Parser::parseCase()
assembly::Statement Parser::parseExpression()
{
Statement operation = parseElementaryOperation(true);
+ if (operation.type() == typeid(Instruction))
+ {
+ Instruction const& instr = boost::get<Instruction>(operation);
+ int args = instructionInfo(instr.instruction).args;
+ if (args > 0 && currentToken() != Token::LParen)
+ fatalParserError(string(
+ "Expected token \"(\" (\"" +
+ instructionNames().at(instr.instruction) +
+ "\" expects " +
+ boost::lexical_cast<string>(args) +
+ " arguments)"
+ ));
+ }
if (currentToken() == Token::LParen)
return parseCall(std::move(operation));
else
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index 276f7bb5..aae6dacd 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -213,6 +213,16 @@ BOOST_AUTO_TEST_CASE(functional)
BOOST_CHECK(successParse("{ let x := 2 add(7, mul(6, x)) mul(7, 8) add =: x }"));
}
+BOOST_AUTO_TEST_CASE(functional_partial)
+{
+ CHECK_PARSE_ERROR("{ let x := byte }", ParserError, "Expected token \"(\"");
+}
+
+BOOST_AUTO_TEST_CASE(functional_partial_success)
+{
+ BOOST_CHECK(successParse("{ let x := byte(1, 2) }"));
+}
+
BOOST_AUTO_TEST_CASE(functional_assignment)
{
BOOST_CHECK(successParse("{ let x := 2 x := 7 }"));
@@ -258,7 +268,7 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case)
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
{
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected.");
- CHECK_PARSE_ERROR("{ 1 2 switch mul default {} }", ParserError, "Instructions are not supported as expressions for switch.");
+ CHECK_PARSE_ERROR("{ switch calldatasize default {} }", ParserError, "Instructions are not supported as expressions for switch.");
}
BOOST_AUTO_TEST_CASE(switch_default_before_case)
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 017eeaec..70934543 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -5785,6 +5785,20 @@ BOOST_AUTO_TEST_CASE(no_unused_inline_asm)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(callable_crash)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; bool x; }
+ S public s;
+ function C() {
+ 3({a: 1, x: true});
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Type is not callable");
+}
+
BOOST_AUTO_TEST_CASE(returndatacopy_as_variable)
{
char const* text = R"(
@@ -5810,7 +5824,6 @@ BOOST_AUTO_TEST_CASE(shadowing_warning_can_be_removed)
}
-
BOOST_AUTO_TEST_SUITE_END()
}