aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/analysis/TypeChecker.cpp18
-rw-r--r--libsolidity/ast/Types.cpp5
-rw-r--r--libsolidity/ast/Types.h1
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp26
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp36
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp13
6 files changed, 99 insertions, 0 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 0d74ddba..756f0e4f 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1253,6 +1253,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
arrayType.isDynamicallySized()
);
}
+ else if (exprType->category() == Type::Category::FixedBytes)
+ annotation.isLValue = false;
return false;
}
@@ -1317,6 +1319,22 @@ bool TypeChecker::visit(IndexAccess const& _access)
}
break;
}
+ case Type::Category::FixedBytes:
+ {
+ FixedBytesType const& bytesType = dynamic_cast<FixedBytesType const&>(*baseType);
+ if (!index)
+ typeError(_access.location(), "Index expression cannot be omitted.");
+ else
+ {
+ expectType(*index, IntegerType(256));
+ if (auto integerType = dynamic_cast<IntegerConstantType const*>(type(*index).get()))
+ if (bytesType.numBytes() <= integerType->literalValue(nullptr))
+ typeError(_access.location(), "Out of bounds array access.");
+ }
+ resultType = make_shared<FixedBytesType>(1);
+ isLValue = false; // @todo this heavily depends on how it is embedded
+ break;
+ }
default:
fatalTypeError(
_access.baseExpression().location(),
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 79e5bb02..01d1cb37 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -638,6 +638,11 @@ TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePoi
return TypePointer();
}
+MemberList::MemberMap FixedBytesType::nativeMembers(const ContractDefinition*) const
+{
+ return MemberList::MemberMap{MemberList::Member{"length", make_shared<IntegerType>(8)}};
+}
+
bool FixedBytesType::operator==(Type const& _other) const
{
if (_other.category() != category())
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 723d633b..90a0509b 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -399,6 +399,7 @@ public:
virtual bool isValueType() const override { return true; }
virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
+ virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
virtual TypePointer encodingType() const override { return shared_from_this(); }
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 9536c727..58db07b1 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1004,6 +1004,16 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
solAssert(false, "Illegal array member.");
break;
}
+ case Type::Category::FixedBytes:
+ {
+ auto const& type = dynamic_cast<FixedBytesType const&>(*_memberAccess.expression().annotation().type);
+ utils().popStackElement(type);
+ if (member == "length")
+ m_context << u256(type.numBytes());
+ else
+ solAssert(false, "Illegal fixed bytes member.");
+ break;
+ }
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type."));
}
@@ -1085,6 +1095,22 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
break;
}
}
+ else if (baseType.category() == Type::Category::FixedBytes)
+ {
+ FixedBytesType const& fixedBytesType = dynamic_cast<FixedBytesType const&>(baseType);
+ solAssert(_indexAccess.indexExpression(), "Index expression expected.");
+
+ _indexAccess.indexExpression()->accept(*this);
+ // stack layout: <value> <index>
+ // check out-of-bounds access
+ m_context << u256(fixedBytesType.numBytes());
+ m_context << eth::Instruction::DUP2 << eth::Instruction::LT << eth::Instruction::ISZERO;
+ // out-of-bounds access throws exception
+ m_context.appendConditionalJumpTo(m_context.errorTag());
+
+ m_context << eth::Instruction::BYTE;
+ m_context << (u256(1) << (256 - 8)) << eth::Instruction::MUL;
+ }
else if (baseType.category() == Type::Category::TypeType)
{
solAssert(baseType.sizeOnStack() == 0, "");
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 73e2d662..c6e1b10d 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -6394,6 +6394,42 @@ BOOST_AUTO_TEST_CASE(inline_long_string_return)
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f()") == encodeDyn(strLong));
}
+
+BOOST_AUTO_TEST_CASE(fixed_bytes_index_access)
+{
+ char const* sourceCode = R"(
+ contract C {
+ bytes16[] public data;
+ function f(bytes32 x) returns (byte) {
+ return x[2];
+ }
+ function g(bytes32 x) returns (uint) {
+ data = [x[0], x[1], x[2]];
+ data[0] = "12345";
+ return uint(data[0][4]);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(bytes32)", "789") == encodeArgs("9"));
+ BOOST_CHECK(callContractFunction("g(bytes32)", "789") == encodeArgs(u256(int('5'))));
+ BOOST_CHECK(callContractFunction("data(uint256)", u256(1)) == encodeArgs("8"));
+}
+
+BOOST_AUTO_TEST_CASE(fixed_bytes_length_access)
+{
+ char const* sourceCode = R"(
+ contract C {
+ byte a;
+ function f(bytes32 x) returns (uint, uint, uint) {
+ return (x.length, bytes16(2).length, a.length + 7);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(bytes32)", "789") == encodeArgs(u256(32), u256(16), u256(8)));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 820fd7d0..d202942c 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -3136,6 +3136,19 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
BOOST_CHECK(success(text));
}
+BOOST_AUTO_TEST_CASE(index_access_for_bytes)
+{
+ char const* text = R"(
+ contract C {
+ bytes20 x;
+ function f(bytes16 b) {
+ b[uint(x[2])];
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}