mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Enforce disallowing empty structs
This patch enfoces an error when it encounters an empty struct, effectively eliminating the deprecation warning. Also adjust 419_interface_structs to explicitely test for (non-empty) structs, as this behaviour "may" change in the future.
This commit is contained in:
parent
014bbc6c97
commit
a211b89118
@ -6,6 +6,7 @@ Breaking Changes:
|
|||||||
* Commandline interface: Remove obsolete ``--formal`` option.
|
* Commandline interface: Remove obsolete ``--formal`` option.
|
||||||
* Commandline interface: Require ``-`` if standard input is used as source.
|
* Commandline interface: Require ``-`` if standard input is used as source.
|
||||||
* General: ``continue`` in a ``do...while`` loop jumps to the condition (it used to jump to the loop body). Warning: this may silently change the semantics of existing code.
|
* General: ``continue`` in a ``do...while`` loop jumps to the condition (it used to jump to the loop body). Warning: this may silently change the semantics of existing code.
|
||||||
|
* General: Disallow declaring empty structs.
|
||||||
* General: Disallow ``sha3`` and ``suicide`` aliases.
|
* General: Disallow ``sha3`` and ``suicide`` aliases.
|
||||||
* General: Introduce ``emit`` as a keyword instead of parsing it as identifier.
|
* General: Introduce ``emit`` as a keyword instead of parsing it as identifier.
|
||||||
* General: New keywords: ``calldata``
|
* General: New keywords: ``calldata``
|
||||||
|
@ -276,14 +276,8 @@ bool SyntaxChecker::visit(VariableDeclaration const& _declaration)
|
|||||||
|
|
||||||
bool SyntaxChecker::visit(StructDefinition const& _struct)
|
bool SyntaxChecker::visit(StructDefinition const& _struct)
|
||||||
{
|
{
|
||||||
bool const v050 = m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeature::V050);
|
|
||||||
|
|
||||||
if (_struct.members().empty())
|
if (_struct.members().empty())
|
||||||
{
|
m_errorReporter.syntaxError(_struct.location(), "Defining empty structs is disallowed.");
|
||||||
if (v050)
|
|
||||||
m_errorReporter.syntaxError(_struct.location(), "Defining empty structs is disallowed.");
|
|
||||||
else
|
|
||||||
m_errorReporter.warning(_struct.location(), "Defining empty structs is deprecated.");
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -659,26 +659,6 @@ BOOST_AUTO_TEST_CASE(struct_function)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(empty_struct)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { }
|
|
||||||
function f(uint a, S s, uint b) public pure returns (uint x, uint y) {
|
|
||||||
assembly { x := a y := b }
|
|
||||||
}
|
|
||||||
function g() public returns (uint, uint) {
|
|
||||||
return this.f(7, S(), 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
ABI_CHECK(callContractFunction("f(uint256,(),uint256)", 7, 8), encodeArgs(7, 8));
|
|
||||||
ABI_CHECK(callContractFunction("g()"), encodeArgs(7, 8));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(mediocre_struct)
|
BOOST_AUTO_TEST_CASE(mediocre_struct)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
|
@ -447,28 +447,6 @@ BOOST_AUTO_TEST_CASE(structs)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(empty_struct)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { }
|
|
||||||
S s;
|
|
||||||
event e(uint16, S, uint16);
|
|
||||||
function f() returns (uint, S, uint) {
|
|
||||||
e(7, s, 8);
|
|
||||||
return (7, s, 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
bytes encoded = encodeArgs(7, 8);
|
|
||||||
BOOST_CHECK(callContractFunction("f()") == encoded);
|
|
||||||
REQUIRE_LOG_DATA(encoded);
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(structs2)
|
BOOST_AUTO_TEST_CASE(structs2)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
|
@ -1271,7 +1271,6 @@ BOOST_AUTO_TEST_CASE(deleteStruct)
|
|||||||
contract test {
|
contract test {
|
||||||
struct topStruct {
|
struct topStruct {
|
||||||
nestedStruct nstr;
|
nestedStruct nstr;
|
||||||
emptyStruct empty;
|
|
||||||
uint topValue;
|
uint topValue;
|
||||||
mapping (uint => uint) topMapping;
|
mapping (uint => uint) topMapping;
|
||||||
}
|
}
|
||||||
@ -1281,8 +1280,6 @@ BOOST_AUTO_TEST_CASE(deleteStruct)
|
|||||||
uint nestedValue;
|
uint nestedValue;
|
||||||
mapping (uint => bool) nestedMapping;
|
mapping (uint => bool) nestedMapping;
|
||||||
}
|
}
|
||||||
struct emptyStruct{
|
|
||||||
}
|
|
||||||
function test(){
|
function test(){
|
||||||
toDelete = 5;
|
toDelete = 5;
|
||||||
str.topValue = 1;
|
str.topValue = 1;
|
||||||
|
@ -203,10 +203,10 @@ BOOST_AUTO_TEST_CASE(external_structs)
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
contract Test {
|
contract Test {
|
||||||
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
|
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
|
||||||
struct Empty {}
|
struct Simple { uint i; }
|
||||||
struct Nested { X[2][] a; uint y; }
|
struct Nested { X[2][] a; uint y; }
|
||||||
struct X { bytes32 x; Test t; Empty[] e; }
|
struct X { bytes32 x; Test t; Simple[] s; }
|
||||||
function f(ActionChoices, uint, Empty) external {}
|
function f(ActionChoices, uint, Simple) external {}
|
||||||
function g(Test, Nested) external {}
|
function g(Test, Nested) external {}
|
||||||
function h(function(Nested) external returns (uint)[]) external {}
|
function h(function(Nested) external returns (uint)[]) external {}
|
||||||
function i(Nested[]) external {}
|
function i(Nested[]) external {}
|
||||||
@ -218,10 +218,10 @@ BOOST_AUTO_TEST_CASE(external_structs)
|
|||||||
{
|
{
|
||||||
auto functions = contract->definedFunctions();
|
auto functions = contract->definedFunctions();
|
||||||
BOOST_REQUIRE(!functions.empty());
|
BOOST_REQUIRE(!functions.empty());
|
||||||
BOOST_CHECK_EQUAL("f(uint8,uint256,())", functions[0]->externalSignature());
|
BOOST_CHECK_EQUAL("f(uint8,uint256,(uint256))", functions[0]->externalSignature());
|
||||||
BOOST_CHECK_EQUAL("g(address,((bytes32,address,()[])[2][],uint256))", functions[1]->externalSignature());
|
BOOST_CHECK_EQUAL("g(address,((bytes32,address,(uint256)[])[2][],uint256))", functions[1]->externalSignature());
|
||||||
BOOST_CHECK_EQUAL("h(function[])", functions[2]->externalSignature());
|
BOOST_CHECK_EQUAL("h(function[])", functions[2]->externalSignature());
|
||||||
BOOST_CHECK_EQUAL("i(((bytes32,address,()[])[2][],uint256)[])", functions[3]->externalSignature());
|
BOOST_CHECK_EQUAL("i(((bytes32,address,(uint256)[])[2][],uint256)[])", functions[3]->externalSignature());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,10 +231,10 @@ BOOST_AUTO_TEST_CASE(external_structs_in_libraries)
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
library Test {
|
library Test {
|
||||||
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
|
enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }
|
||||||
struct Empty {}
|
struct Simple { uint i; }
|
||||||
struct Nested { X[2][] a; uint y; }
|
struct Nested { X[2][] a; uint y; }
|
||||||
struct X { bytes32 x; Test t; Empty[] e; }
|
struct X { bytes32 x; Test t; Simple[] s; }
|
||||||
function f(ActionChoices, uint, Empty) external {}
|
function f(ActionChoices, uint, Simple) external {}
|
||||||
function g(Test, Nested) external {}
|
function g(Test, Nested) external {}
|
||||||
function h(function(Nested) external returns (uint)[]) external {}
|
function h(function(Nested) external returns (uint)[]) external {}
|
||||||
function i(Nested[]) external {}
|
function i(Nested[]) external {}
|
||||||
@ -246,7 +246,7 @@ BOOST_AUTO_TEST_CASE(external_structs_in_libraries)
|
|||||||
{
|
{
|
||||||
auto functions = contract->definedFunctions();
|
auto functions = contract->definedFunctions();
|
||||||
BOOST_REQUIRE(!functions.empty());
|
BOOST_REQUIRE(!functions.empty());
|
||||||
BOOST_CHECK_EQUAL("f(Test.ActionChoices,uint256,Test.Empty)", functions[0]->externalSignature());
|
BOOST_CHECK_EQUAL("f(Test.ActionChoices,uint256,Test.Simple)", functions[0]->externalSignature());
|
||||||
BOOST_CHECK_EQUAL("g(Test,Test.Nested)", functions[1]->externalSignature());
|
BOOST_CHECK_EQUAL("g(Test,Test.Nested)", functions[1]->externalSignature());
|
||||||
BOOST_CHECK_EQUAL("h(function[])", functions[2]->externalSignature());
|
BOOST_CHECK_EQUAL("h(function[])", functions[2]->externalSignature());
|
||||||
BOOST_CHECK_EQUAL("i(Test.Nested[])", functions[3]->externalSignature());
|
BOOST_CHECK_EQUAL("i(Test.Nested[])", functions[3]->externalSignature());
|
||||||
|
@ -2,4 +2,4 @@ contract test {
|
|||||||
struct A {}
|
struct A {}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning: (17-28): Defining empty structs is deprecated.
|
// SyntaxError: (17-28): Defining empty structs is disallowed.
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
pragma experimental "v0.5.0";
|
|
||||||
contract test {
|
|
||||||
struct A {}
|
|
||||||
}
|
|
||||||
// ----
|
|
||||||
// SyntaxError: (47-58): Defining empty structs is disallowed.
|
|
@ -1,13 +1,11 @@
|
|||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
contract C {
|
contract C {
|
||||||
struct S1 { }
|
struct S1 { int i; }
|
||||||
struct S2 { }
|
struct S2 { int i; }
|
||||||
function f(S1) pure {}
|
function f(S1) pure {}
|
||||||
function f(S2) pure {}
|
function f(S2) pure {}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
|
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
|
||||||
// Warning: (52-65): Defining empty structs is deprecated.
|
// TypeError: (129-151): Function overload clash during conversion to external types for arguments.
|
||||||
// Warning: (70-83): Defining empty structs is deprecated.
|
|
||||||
// TypeError: (115-137): Function overload clash during conversion to external types for arguments.
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
interface I {
|
interface I {
|
||||||
struct A {
|
struct A {
|
||||||
|
// This is currently expected to break, but it *may* change in the future.
|
||||||
|
int dummy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning: (18-34): Defining empty structs is deprecated.
|
// TypeError: (18-136): Structs cannot be defined in interfaces.
|
||||||
// TypeError: (18-34): Structs cannot be defined in interfaces.
|
// TypeError: (120-129): Variables cannot be declared in interfaces.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
contract C {
|
contract C {
|
||||||
struct S { uint x; }
|
struct S { uint x; }
|
||||||
S s;
|
S s;
|
||||||
struct T { }
|
struct T { uint y; }
|
||||||
T t;
|
T t;
|
||||||
enum A { X, Y }
|
enum A { X, Y }
|
||||||
function f() public pure {
|
function f() public pure {
|
||||||
@ -9,9 +9,8 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning: (51-63): Defining empty structs is deprecated.
|
// TypeError: (176-177): This type cannot be encoded.
|
||||||
// TypeError: (168-169): This type cannot be encoded.
|
|
||||||
// TypeError: (171-172): This type cannot be encoded.
|
|
||||||
// TypeError: (179-180): This type cannot be encoded.
|
// TypeError: (179-180): This type cannot be encoded.
|
||||||
// TypeError: (182-186): This type cannot be encoded.
|
// TypeError: (187-188): This type cannot be encoded.
|
||||||
// TypeError: (188-194): This type cannot be encoded.
|
// TypeError: (190-194): This type cannot be encoded.
|
||||||
|
// TypeError: (196-202): This type cannot be encoded.
|
||||||
|
Loading…
Reference in New Issue
Block a user