aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md10
-rw-r--r--docs/control-structures.rst11
-rw-r--r--docs/introduction-to-smart-contracts.rst4
-rw-r--r--docs/types.rst3
-rw-r--r--libsolidity/analysis/TypeChecker.cpp4
-rw-r--r--libsolidity/ast/AST.h8
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp6
-rw-r--r--libsolidity/ast/ASTPrinter.cpp2
-rw-r--r--libsolidity/ast/Types.cpp17
-rw-r--r--libsolidity/ast/Types.h1
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp19
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp19
-rw-r--r--libsolidity/formal/Why3Translator.cpp10
-rw-r--r--libsolidity/grammar.txt3
-rw-r--r--libsolidity/parsing/Parser.cpp21
-rw-r--r--libsolidity/parsing/Parser.h1
-rw-r--r--test/libsolidity/ASTJSON.cpp14
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp78
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp15
-rw-r--r--test/libsolidity/SolidityParser.cpp2
20 files changed, 207 insertions, 41 deletions
diff --git a/Changelog.md b/Changelog.md
index ee106047..851f39a0 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,15 @@
### 0.4.5 (unreleased)
+Features:
+ * Do-while loops: support for a C-style do{<block>}while(<expr>); control structure
+ * Type checker: now more eagerly searches for a common type of an inline array with mixed types
+ * Code generator: generates a runtime error when an out-of-range value is converted into an enum type.
+
+Bugfixes:
+
+ * Parser: disallow empty enum definitions.
+ * Type checker: disallow conversion between different enum types.
+
### 0.4.4 (2016-10-31)
Bugfixes:
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 597829d3..bbb90e6a 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -2,14 +2,14 @@
Expressions and Control Structures
##################################
-.. index:: if, else, while, for, break, continue, return, switch, goto
+.. index:: if, else, while, do/while, for, break, continue, return, switch, goto
Control Structures
===================
Most of the control structures from C or JavaScript are available in Solidity
except for ``switch`` and ``goto``. So
-there is: ``if``, ``else``, ``while``, ``for``, ``break``, ``continue``, ``return``, ``? :``, with
+there is: ``if``, ``else``, ``while``, ``do``, ``for``, ``break``, ``continue``, ``return``, ``? :``, with
the usual semantics known from C or JavaScript.
Parentheses can *not* be omitted for conditionals, but curly brances can be omitted
@@ -329,9 +329,10 @@ Currently, there are situations, where exceptions happen automatically in Solidi
3. If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation ``call``, ``send``, ``delegatecall`` or ``callcode`` is used. The low level operations never throw exceptions but indicate failures by returning ``false``.
4. If you create a contract using the ``new`` keyword but the contract creation does not finish properly (see above for the definition of "not finish properly").
5. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``).
-6. If you perform an external function call targeting a contract that contains no code.
-7. If your contract receives Ether via a public function without ``payable`` modifier (including the constructor and the fallback function).
-8. If your contract receives Ether via a public accessor function.
+6. If you convert a value too big or negative into an enum type.
+7. If you perform an external function call targeting a contract that contains no code.
+8. If your contract receives Ether via a public function without ``payable`` modifier (including the constructor and the fallback function).
+9. If your contract receives Ether via a public accessor function.
Internally, Solidity performs an "invalid jump" when an exception is thrown and thus causes the EVM to revert all changes made to the state. The reason for this is that there is no safe way to continue execution, because an expected effect did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction (or at least call) without effect.
diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst
index eeea85a7..4a3de441 100644
--- a/docs/introduction-to-smart-contracts.rst
+++ b/docs/introduction-to-smart-contracts.rst
@@ -25,7 +25,7 @@ Storage
storedData = x;
}
- function get() constant returns (uint retVal) {
+ function get() constant returns (uint) {
return storedData;
}
}
@@ -136,7 +136,7 @@ like this one. The accessor function created by the ``public`` keyword
is a bit more complex in this case. It roughly looks like the
following::
- function balances(address _account) returns (uint balance) {
+ function balances(address _account) returns (uint) {
return balances[_account];
}
diff --git a/docs/types.rst b/docs/types.rst
index 9e7d9b4a..9ec9e526 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -237,7 +237,8 @@ Enums
=====
Enums are one way to create a user-defined type in Solidity. They are explicitly convertible
-to and from all integer types but implicit conversion is not allowed.
+to and from all integer types but implicit conversion is not allowed. The explicit conversions
+check the value ranges at runtime and a failure causes an exception. Enums needs at least one member.
::
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 46f4f7f6..f934b2c8 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -996,9 +996,9 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
fatalTypeError(components[i]->location(), "Invalid mobile type.");
if (i == 0)
- inlineArrayType = types[i]->mobileType();
+ inlineArrayType = types[i];
else if (inlineArrayType)
- inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType());
+ inlineArrayType = Type::commonType(inlineArrayType, types[i]);
}
}
else
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 7ed4ddce..6c3f52bc 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -1005,18 +1005,22 @@ public:
SourceLocation const& _location,
ASTPointer<ASTString> const& _docString,
ASTPointer<Expression> const& _condition,
- ASTPointer<Statement> const& _body
+ ASTPointer<Statement> const& _body,
+ bool _isDoWhile
):
- BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body) {}
+ BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body),
+ m_isDoWhile(_isDoWhile) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
Expression const& condition() const { return *m_condition; }
Statement const& body() const { return *m_body; }
+ bool isDoWhile() const { return m_isDoWhile; }
private:
ASTPointer<Expression> m_condition;
ASTPointer<Statement> m_body;
+ bool m_isDoWhile;
};
/**
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index b573feda..3fce1180 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -264,7 +264,11 @@ bool ASTJsonConverter::visit(IfStatement const& _node)
bool ASTJsonConverter::visit(WhileStatement const& _node)
{
- addJsonNode(_node, "WhileStatement", {}, true);
+ addJsonNode(
+ _node,
+ _node.isDoWhile() ? "DoWhileStatement" : "WhileStatement",
+ {},
+ true);
return true;
}
diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp
index a9de457a..27266968 100644
--- a/libsolidity/ast/ASTPrinter.cpp
+++ b/libsolidity/ast/ASTPrinter.cpp
@@ -208,7 +208,7 @@ bool ASTPrinter::visit(IfStatement const& _node)
bool ASTPrinter::visit(WhileStatement const& _node)
{
- writeLine("WhileStatement");
+ writeLine(_node.isDoWhile() ? "DoWhileStatement" : "WhileStatement");
printSourcePart(_node);
return goDeeper();
}
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 7fe97fa7..f0995393 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -200,10 +200,10 @@ TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
{
if (!_a || !_b)
return TypePointer();
- else if (_b->isImplicitlyConvertibleTo(*_a))
- return _a;
- else if (_a->isImplicitlyConvertibleTo(*_b))
- return _b;
+ else if (_b->isImplicitlyConvertibleTo(*_a->mobileType()))
+ return _a->mobileType();
+ else if (_a->isImplicitlyConvertibleTo(*_b->mobileType()))
+ return _b->mobileType();
else
return TypePointer();
}
@@ -1561,7 +1561,7 @@ bool EnumType::operator==(Type const& _other) const
unsigned EnumType::storageBytes() const
{
- size_t elements = m_enum.members().size();
+ size_t elements = numberOfMembers();
if (elements <= 1)
return 1;
else
@@ -1578,9 +1578,14 @@ string EnumType::canonicalName(bool) const
return m_enum.annotation().canonicalName;
}
+size_t EnumType::numberOfMembers() const
+{
+ return m_enum.members().size();
+};
+
bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
+ return _convertTo == *this || _convertTo.category() == Category::Integer;
}
unsigned EnumType::memberValue(ASTString const& _member) const
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 3f94d11a..082e16a6 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -738,6 +738,7 @@ public:
EnumDefinition const& enumDefinition() const { return m_enum; }
/// @returns the value that the string has in the Enum
unsigned int memberValue(ASTString const& _member) const;
+ size_t numberOfMembers() const;
private:
EnumDefinition const& m_enum;
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index e064c1a6..dd133aea 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -315,6 +315,8 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
Type::Category stackTypeCategory = _typeOnStack.category();
Type::Category targetTypeCategory = _targetType.category();
+ bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum);
+
switch (stackTypeCategory)
{
case Type::Category::FixedBytes:
@@ -348,7 +350,15 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
}
break;
case Type::Category::Enum:
- solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Enum, "");
+ solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, "");
+ if (enumOverflowCheckPending)
+ {
+ EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType);
+ solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error.");
+ m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT;
+ m_context.appendConditionalJumpTo(m_context.errorTag());
+ enumOverflowCheckPending = false;
+ }
break;
case Type::Category::FixedPoint:
solAssert(false, "Not yet implemented - FixedPointType.");
@@ -372,6 +382,11 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
solAssert(_typeOnStack.mobileType(), "");
// just clean
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
+ EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType);
+ solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error.");
+ m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT;
+ m_context.appendConditionalJumpTo(m_context.errorTag());
+ enumOverflowCheckPending = false;
}
else if (targetTypeCategory == Type::Category::FixedPoint)
{
@@ -656,6 +671,8 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
break;
}
+
+ solAssert(!enumOverflowCheckPending, "enum overflow checking missing.");
}
void CompilerUtils::pushZeroValue(Type const& _type)
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index ebb84784..1404963f 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -611,12 +611,25 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement)
m_breakTags.push_back(loopEnd);
m_context << loopStart;
- compileExpression(_whileStatement.condition());
- m_context << Instruction::ISZERO;
- m_context.appendConditionalJumpTo(loopEnd);
+
+ // While loops have the condition prepended
+ if (!_whileStatement.isDoWhile())
+ {
+ compileExpression(_whileStatement.condition());
+ m_context << Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(loopEnd);
+ }
_whileStatement.body().accept(*this);
+ // Do-while loops have the condition appended
+ if (_whileStatement.isDoWhile())
+ {
+ compileExpression(_whileStatement.condition());
+ m_context << Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(loopEnd);
+ }
+
m_context.appendJumpTo(loopStart);
m_context << loopEnd;
diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp
index 813fa3ab..5934d593 100644
--- a/libsolidity/formal/Why3Translator.cpp
+++ b/libsolidity/formal/Why3Translator.cpp
@@ -410,6 +410,16 @@ bool Why3Translator::visit(WhileStatement const& _node)
{
addSourceFromDocStrings(_node.annotation());
+ // Why3 does not appear to support do-while loops,
+ // so we will simulate them by performing a while
+ // loop with the body prepended once.
+
+ if (_node.isDoWhile())
+ {
+ visitIndentedUnlessBlock(_node.body());
+ newLine();
+ }
+
add("while ");
_node.condition().accept(*this);
newLine();
diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt
index d84ee10c..3edb4eba 100644
--- a/libsolidity/grammar.txt
+++ b/libsolidity/grammar.txt
@@ -42,7 +42,7 @@ StorageLocation = 'memory' | 'storage'
Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | ForStatement | Block |
- ( PlaceholderStatement | Continue | Break | Return |
+ ( DoWhileStatement | PlaceholderStatement | Continue | Break | Return |
Throw | SimpleStatement ) ';'
ExpressionStatement = Expression
@@ -51,6 +51,7 @@ WhileStatement = 'while' '(' Expression ')' Statement
PlaceholderStatement = '_'
SimpleStatement = VariableDefinition | ExpressionStatement
ForStatement = 'for' '(' (SimpleStatement)? ';' (Expression)? ';' (ExpressionStatement)? ')' Statement
+DoWhileStatement = 'do' Statement 'while' '(' Expression ')'
Continue = 'continue'
Break = 'break'
Return = 'return' Expression?
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index 0e99d1e7..df3ed7b2 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -406,6 +406,8 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition()
if (m_scanner->currentToken() != Token::Identifier)
fatalParserError(string("Expected Identifier after ','"));
}
+ if (members.size() == 0)
+ parserError({"enum with no members is not allowed."});
nodeFactory.markEndPosition();
expectToken(Token::RBrace);
@@ -722,6 +724,8 @@ ASTPointer<Statement> Parser::parseStatement()
return parseIfStatement(docString);
case Token::While:
return parseWhileStatement(docString);
+ case Token::Do:
+ return parseDoWhileStatement(docString);
case Token::For:
return parseForStatement(docString);
case Token::LBrace:
@@ -816,9 +820,24 @@ ASTPointer<WhileStatement> Parser::parseWhileStatement(ASTPointer<ASTString> con
expectToken(Token::RParen);
ASTPointer<Statement> body = parseStatement();
nodeFactory.setEndPositionFromNode(body);
- return nodeFactory.createNode<WhileStatement>(_docString, condition, body);
+ return nodeFactory.createNode<WhileStatement>(_docString, condition, body, false);
}
+ASTPointer<WhileStatement> Parser::parseDoWhileStatement(ASTPointer<ASTString> const& _docString)
+{
+ ASTNodeFactory nodeFactory(*this);
+ expectToken(Token::Do);
+ ASTPointer<Statement> body = parseStatement();
+ expectToken(Token::While);
+ expectToken(Token::LParen);
+ ASTPointer<Expression> condition = parseExpression();
+ expectToken(Token::RParen);
+ nodeFactory.markEndPosition();
+ expectToken(Token::Semicolon);
+ return nodeFactory.createNode<WhileStatement>(_docString, condition, body, true);
+}
+
+
ASTPointer<ForStatement> Parser::parseForStatement(ASTPointer<ASTString> const& _docString)
{
ASTNodeFactory nodeFactory(*this);
diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h
index 9c30cf60..26f347cb 100644
--- a/libsolidity/parsing/Parser.h
+++ b/libsolidity/parsing/Parser.h
@@ -85,6 +85,7 @@ private:
ASTPointer<InlineAssembly> parseInlineAssembly(ASTPointer<ASTString> const& _docString = {});
ASTPointer<IfStatement> parseIfStatement(ASTPointer<ASTString> const& _docString);
ASTPointer<WhileStatement> parseWhileStatement(ASTPointer<ASTString> const& _docString);
+ ASTPointer<WhileStatement> parseDoWhileStatement(ASTPointer<ASTString> const& _docString);
ASTPointer<ForStatement> parseForStatement(ASTPointer<ASTString> const& _docString);
/// A "simple statement" can be a variable declaration statement or an expression statement.
ASTPointer<Statement> parseSimpleStatement(ASTPointer<ASTString> const& _docString);
diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp
index a0fc5dd7..6c062ee8 100644
--- a/test/libsolidity/ASTJSON.cpp
+++ b/test/libsolidity/ASTJSON.cpp
@@ -94,20 +94,6 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint");
}
-BOOST_AUTO_TEST_CASE(enum_definition)
-{
- CompilerStack c;
- c.addSource("a", "contract C { enum E {} }");
- c.parse();
- map<string, unsigned> sourceIndices;
- sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
- Json::Value enumDefinition = astJson["children"][0]["children"][0];
- BOOST_CHECK_EQUAL(enumDefinition["name"], "EnumDefinition");
- BOOST_CHECK_EQUAL(enumDefinition["attributes"]["name"], "E");
- BOOST_CHECK_EQUAL(enumDefinition["src"], "13:9:1");
-}
-
BOOST_AUTO_TEST_CASE(enum_value)
{
CompilerStack c;
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 8600443d..5582e4a1 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -353,6 +353,34 @@ BOOST_AUTO_TEST_CASE(while_loop)
testSolidityAgainstCppOnRange("f(uint256)", while_loop_cpp, 0, 5);
}
+
+BOOST_AUTO_TEST_CASE(do_while_loop)
+{
+ char const* sourceCode = "contract test {\n"
+ " function f(uint n) returns(uint nfac) {\n"
+ " nfac = 1;\n"
+ " var i = 2;\n"
+ " do { nfac *= i++; } while (i <= n);\n"
+ " }\n"
+ "}\n";
+ compileAndRun(sourceCode);
+
+ auto do_while_loop_cpp = [](u256 const& n) -> u256
+ {
+ u256 nfac = 1;
+ u256 i = 2;
+ do
+ {
+ nfac *= i++;
+ }
+ while (i <= n);
+
+ return nfac;
+ };
+
+ testSolidityAgainstCppOnRange("f(uint256)", do_while_loop_cpp, 0, 5);
+}
+
BOOST_AUTO_TEST_CASE(nested_loops)
{
// tests that break and continue statements in nested loops jump to the correct place
@@ -3314,6 +3342,42 @@ BOOST_AUTO_TEST_CASE(using_enums)
BOOST_CHECK(callContractFunction("getChoice()") == encodeArgs(2));
}
+BOOST_AUTO_TEST_CASE(enum_explicit_overflow)
+{
+ char const* sourceCode = R"(
+ contract test {
+ enum ActionChoices { GoLeft, GoRight, GoStraight }
+ function test()
+ {
+ }
+ function getChoiceExp(uint x) returns (uint d)
+ {
+ choice = ActionChoices(x);
+ d = uint256(choice);
+ }
+ function getChoiceFromSigned(int x) returns (uint d)
+ {
+ choice = ActionChoices(x);
+ d = uint256(choice);
+ }
+ function getChoiceFromNegativeLiteral() returns (uint d)
+ {
+ choice = ActionChoices(-1);
+ d = uint256(choice);
+ }
+ ActionChoices choice;
+ }
+ )";
+ compileAndRun(sourceCode);
+ // These should throw
+ BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 3) == encodeArgs());
+ BOOST_CHECK(callContractFunction("getChoiceFromSigned(int256)", -1) == encodeArgs());
+ BOOST_CHECK(callContractFunction("getChoiceFromNegativeLiteral()") == encodeArgs());
+ // These should work
+ BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 2) == encodeArgs(2));
+ BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 0) == encodeArgs(0));
+}
+
BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name)
{
char const* sourceCode = R"(
@@ -6325,6 +6389,20 @@ BOOST_AUTO_TEST_CASE(decayed_tuple)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2)));
}
+BOOST_AUTO_TEST_CASE(inline_tuple_with_rational_numbers)
+{
+ char const* sourceCode = R"(
+ contract c {
+ function f() returns (int8) {
+ int8[5] memory foo3 = [int8(1), -1, 0, 0, 0];
+ return foo3[0];
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
+}
+
BOOST_AUTO_TEST_CASE(destructuring_assignment)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 099c3c00..f498a0b9 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -1535,6 +1535,21 @@ BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay)
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
+BOOST_AUTO_TEST_CASE(enum_to_enum_conversion_is_not_okay)
+{
+ char const* text = R"(
+ contract test {
+ enum Paper { Up, Down, Left, Right }
+ enum Ground { North, South, West, East }
+ function test()
+ {
+ Ground(Paper.Up);
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
BOOST_AUTO_TEST_CASE(enum_duplicate_values)
{
char const* text = R"(
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index a81a9828..ec23d5fd 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -824,7 +824,7 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration)
contract c {
enum foo { }
})";
- BOOST_CHECK(successParse(text));
+ BOOST_CHECK(!successParse(text));
}
BOOST_AUTO_TEST_CASE(malformed_enum_declaration)