aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md1
-rw-r--r--libsolidity/analysis/TypeChecker.cpp10
-rw-r--r--libsolidity/analysis/TypeChecker.h3
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp62
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/419_interface_structs.sol3
5 files changed, 72 insertions, 7 deletions
diff --git a/Changelog.md b/Changelog.md
index 7e0e5618..732c0a7f 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -75,6 +75,7 @@ Language Features:
* General: Scoping rules now follow the C99-style.
* General: Allow ``enum``s in interfaces.
* General: Allow ``mapping`` storage pointers as arguments and return values in all internal functions.
+ * General: Allow ``struct``s in interfaces.
Compiler Features:
* C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 0ffe6636..601a5e7c 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -580,9 +580,6 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
bool TypeChecker::visit(StructDefinition const& _struct)
{
- if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface)
- m_errorReporter.typeError(_struct.location(), "Structs cannot be defined in interfaces.");
-
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
if (!type(*member)->canBeStored())
m_errorReporter.typeError(member->location(), "Type cannot be used in struct.");
@@ -610,7 +607,10 @@ bool TypeChecker::visit(StructDefinition const& _struct)
if (CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
m_errorReporter.fatalTypeError(_struct.location(), "Recursive struct definition.");
+ bool insideStruct = true;
+ swap(insideStruct, m_insideStruct);
ASTNode::listAccept(_struct.members(), *this);
+ m_insideStruct = insideStruct;
return false;
}
@@ -693,10 +693,12 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
bool TypeChecker::visit(VariableDeclaration const& _variable)
{
// Forbid any variable declarations inside interfaces unless they are part of
- // a function's input/output parameters.
+ // * a function's input/output parameters,
+ // * or inside of a struct definition.
if (
m_scope->contractKind() == ContractDefinition::ContractKind::Interface
&& !_variable.isCallableParameter()
+ && !m_insideStruct
)
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index b696de85..ed316f9c 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -149,6 +149,9 @@ private:
/// Flag indicating whether we are currently inside an EmitStatement.
bool m_insideEmitStatement = false;
+ /// Flag indicating whether we are currently inside a StructDefinition.
+ bool m_insideStruct = false;
+
ErrorReporter& m_errorReporter;
};
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index d8e95ad2..7b56fa9d 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -4755,6 +4755,68 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints)
ABI_CHECK(callContractFunction("test()"), encodeArgs(1));
}
+BOOST_AUTO_TEST_CASE(struct_referencing)
+{
+ static char const* sourceCode = R"(
+ pragma experimental ABIEncoderV2;
+ interface I {
+ struct S { uint a; }
+ }
+ library L {
+ struct S { uint b; uint a; }
+ function f() public pure returns (S) {
+ S memory s;
+ s.a = 3;
+ return s;
+ }
+ function g() public pure returns (I.S) {
+ I.S memory s;
+ s.a = 4;
+ return s;
+ }
+ // argument-dependant lookup tests
+ function a(I.S memory) public pure returns (uint) { return 1; }
+ function a(S memory) public pure returns (uint) { return 2; }
+ }
+ contract C is I {
+ function f() public pure returns (S) {
+ S memory s;
+ s.a = 1;
+ return s;
+ }
+ function g() public pure returns (I.S) {
+ I.S memory s;
+ s.a = 2;
+ return s;
+ }
+ function h() public pure returns (L.S) {
+ L.S memory s;
+ s.a = 5;
+ return s;
+ }
+ function x() public pure returns (L.S) {
+ return L.f();
+ }
+ function y() public pure returns (I.S) {
+ return L.g();
+ }
+ function a1() public pure returns (uint) { S memory s; return L.a(s); }
+ function a2() public pure returns (uint) { L.S memory s; return L.a(s); }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "L");
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 3));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(4));
+ compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{ {"L", m_contractAddress}});
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(2));
+ ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 5));
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(0, 3));
+ ABI_CHECK(callContractFunction("y()"), encodeArgs(4));
+ ABI_CHECK(callContractFunction("a1()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("a2()"), encodeArgs(2));
+}
+
BOOST_AUTO_TEST_CASE(enum_referencing)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/419_interface_structs.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/419_interface_structs.sol
index c74d52d3..385ed18e 100644
--- a/test/libsolidity/syntaxTests/nameAndTypeResolution/419_interface_structs.sol
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/419_interface_structs.sol
@@ -1,9 +1,6 @@
interface I {
struct A {
- // This is currently expected to break, but it *may* change in the future.
int dummy;
}
}
// ----
-// TypeError: (18-136): Structs cannot be defined in interfaces.
-// TypeError: (120-129): Variables cannot be declared in interfaces.