aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md6
-rw-r--r--docs/index.rst64
-rw-r--r--libsolidity/analysis/TypeChecker.cpp54
-rw-r--r--libsolidity/ast/Types.cpp8
-rw-r--r--libsolidity/ast/Types.h2
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp2
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp18
-rw-r--r--libsolidity/codegen/CompilerUtils.h2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp16
-rw-r--r--scripts/Dockerfile_alpine5
-rwxr-xr-xscripts/docker_build.sh4
-rwxr-xr-xscripts/docker_deploy.sh24
-rwxr-xr-xscripts/docker_deploy_manual.sh27
-rw-r--r--solc/CommandLineInterface.cpp16
-rw-r--r--test/libsolidity/SMTCheckerJSONTest.cpp87
-rw-r--r--test/libsolidity/syntaxTests/functionTypes/function_type_struct.sol8
-rw-r--r--test/libsolidity/syntaxTests/functionTypes/function_type_struct_undefined_member.sol11
-rw-r--r--test/libsolidity/syntaxTests/getter/complex_struct.sol7
-rw-r--r--test/libsolidity/syntaxTests/getter/nested_structs.sol11
-rw-r--r--test/libsolidity/syntaxTests/getter/recursive_struct.sol8
-rw-r--r--test/libsolidity/syntaxTests/getter/simple_struct.sol6
21 files changed, 258 insertions, 128 deletions
diff --git a/Changelog.md b/Changelog.md
index a90580bc..f64ae184 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -16,12 +16,16 @@ Compiler Features:
Bugfixes:
* Assembly output: Do not mix in/out jump annotations with arguments.
+ * Commandline interface: Fix crash when using ``--ast`` on empty runtime code.
* Code Generator: Annotate jump from calldata decoder to function as "jump in".
- * Type Checker: Properly detect different return types when overriding an external interface function with a public contract function.
* Optimizer: Fix nondeterminism bug related to the boost version and constants representation. The bug only resulted in less optimal but still correct code because the generated routine is always verified to be correct.
+ * Type Checker: Properly detect different return types when overriding an external interface function with a public contract function.
+ * Type Checker: Disallow struct return types for getters of public state variables unless the new ABI encoder is active.
+ * Type Checker: Fix internal compiler error when a field of a struct used as a parameter in a function type has a non-existent type.
Build System:
* Emscripten: Upgrade to Emscripten SDK 1.37.21 and boost 1.67.
+ * Docker: Includes both Scratch and Alpine images.
diff --git a/docs/index.rst b/docs/index.rst
index 17abf4b2..ed931163 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,26 +19,43 @@ user-defined types among other features.
With Solidity you can create contracts for uses such as voting, crowdfunding, blind auctions,
and multi-signature wallets.
-.. note::
- The best way to try out Solidity right now is using
- `Remix <https://remix.ethereum.org/>`_
- (it can take a while to load, please be patient). Remix is a web browser
- based IDE that allows you to write Solidity smart contracts, then deploy
- and run the smart contracts.
+Language Documentation
+----------------------
+
+If you are new to the concept of smart contracts we recommend you start with
+:ref:`an example smart contract <simple-smart-contract>` written
+in Solidity. When you are ready for more detail, we recommend you read the
+:doc:`"Solidity by Example" <solidity-by-example>` and :doc:`"Solidity in Depth" <solidity-in-depth>` sections to learn the core concepts of the language.
+
+For further reading, try :ref:`the basics of blockchains <blockchain-basics>`
+and details of the :ref:`Ethereum Virtual Machine <the-ethereum-virtual-machine>`.
+
+.. hint::
+ You can always try out code examples in your browser with the
+ `Remix IDE <https://remix.ethereum.org>`_. Remix is a web browser based IDE
+ that allows you to write Solidity smart contracts, then deploy and run the
+ smart contracts. It can take a while to load, so please be patient.
.. warning::
- Since software is written by humans, it can have bugs. Thus, also
- smart contracts should be created following well-known best-practices in
- software development. This includes code review, testing, audits and correctness proofs.
- Also note that users are sometimes more confident in code than its authors.
- Finally, blockchains have their own things to watch out for, so please take
- a look at the section :ref:`security_considerations`.
+ As humans write software, it can have bugs. You should follow established
+ software development best-practices when writing your smart contracts, this
+ includes code review, testing, audits, and correctness proofs. Smart contract
+ users are sometimes more confident with code than their authors, and
+ blockchains and smart contracts have their own unique issues to
+ watch out for, so before working on production code, make sure you read the
+ :ref:`security_considerations` section.
+
+If you have any questions, you can try searching for answers or asking on the
+`Ethereum Stackexchange <https://ethereum.stackexchange.com/>`_, or our `gitter channel <https://gitter.im/ethereum/solidity/>`_.
+
+Ideas for improving Solidity or this documentation are always welcome, read our :doc:`contributors guide <contributing>` for more details.
Translations
------------
-This documentation is translated into several languages by community volunteers
-with varying degrees of completeness and up-to-dateness. The English version stands as a reference.
+Community volunteers help translate this documentation into several languages.
+They have varying degrees of completeness and up-to-dateness. The English
+version stands as a reference.
* `Simplified Chinese <http://solidity-cn.readthedocs.io>`_ (in progress)
* `Spanish <https://solidity-es.readthedocs.io>`_
@@ -46,25 +63,6 @@ with varying degrees of completeness and up-to-dateness. The English version sta
* `Korean <http://solidity-kr.readthedocs.io>`_ (in progress)
* `French <http://solidity-fr.readthedocs.io>`_ (in progress)
-Language Documentation
-----------------------
-
-On the next pages, we will first see a :ref:`simple smart contract <simple-smart-contract>` written
-in Solidity followed by the basics about :ref:`blockchains <blockchain-basics>`
-and the :ref:`Ethereum Virtual Machine <the-ethereum-virtual-machine>`.
-
-The next section will explain several *features* of Solidity by giving
-useful :ref:`example contracts <voting>`.
-Remember that you can always try out the contracts
-`in your browser <https://remix.ethereum.org>`_!
-
-The fourth and most extensive section will cover all aspects of Solidity in depth.
-
-If you still have questions, you can try searching or asking on the
-`Ethereum Stackexchange <https://ethereum.stackexchange.com/>`_
-site, or come to our `gitter channel <https://gitter.im/ethereum/solidity/>`_.
-Ideas for improving Solidity or this documentation are always welcome!
-
Contents
========
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 9d536a3a..fcc6746f 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -21,17 +21,24 @@
*/
#include <libsolidity/analysis/TypeChecker.h>
-#include <memory>
-#include <boost/algorithm/cxx11/all_of.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/algorithm/string/join.hpp>
-#include <boost/range/adaptor/reversed.hpp>
#include <libsolidity/ast/AST.h>
+
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/AsmData.h>
+
#include <liblangutil/ErrorReporter.h>
+
#include <libdevcore/Algorithms.h>
+#include <libdevcore/StringUtils.h>
+
+#include <boost/algorithm/cxx11/all_of.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/join.hpp>
+#include <boost/range/adaptor/reversed.hpp>
+
+#include <memory>
+#include <vector>
using namespace std;
using namespace dev;
@@ -777,15 +784,10 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
)
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
- // Variables can be declared without type (with "var"), in which case the first assignment
- // sets the type.
- // Note that assignments before the first declaration are legal because of the special scoping
- // rules inherited from JavaScript.
-
// type is filled either by ReferencesResolver directly from the type name or by
// TypeChecker at the VariableDeclarationStatement level.
TypePointer varType = _variable.annotation().type;
- solAssert(!!varType, "Failed to infer variable type.");
+ solAssert(!!varType, "Variable type not provided.");
if (_variable.value())
expectType(*_variable.value(), *varType);
@@ -814,11 +816,25 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
if (!varType->canLiveOutsideStorage())
m_errorReporter.typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage.");
}
- else if (
- _variable.visibility() >= VariableDeclaration::Visibility::Public &&
- !FunctionType(_variable).interfaceFunctionType()
- )
- m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
+ else if (_variable.visibility() >= VariableDeclaration::Visibility::Public)
+ {
+ FunctionType getter(_variable);
+ if (!_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
+ {
+ vector<string> unsupportedTypes;
+ for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes())
+ if (!typeSupportedByOldABIEncoder(*param))
+ unsupportedTypes.emplace_back(param->toString());
+ if (!unsupportedTypes.empty())
+ m_errorReporter.typeError(_variable.location(),
+ "The following types are only supported for getters in the new experimental ABI encoder: " +
+ joinHumanReadable(unsupportedTypes) +
+ ". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature."
+ );
+ }
+ if (!getter.interfaceFunctionType())
+ m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
+ }
switch (varType->category())
{
@@ -2490,7 +2506,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
}
else
{
- expectType(*index, IntegerType(256));
+ expectType(*index, IntegerType::uint256());
if (!m_errorReporter.hasErrors())
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
{
@@ -2521,7 +2537,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
else
{
- expectType(*index, IntegerType(256));
+ expectType(*index, IntegerType::uint256());
if (auto length = dynamic_cast<RationalNumberType const*>(type(*index).get()))
resultType = make_shared<TypeType>(make_shared<ArrayType>(
DataLocation::Memory,
@@ -2540,7 +2556,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
else
{
- if (!expectType(*index, IntegerType(256)))
+ if (!expectType(*index, IntegerType::uint256()))
m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer.");
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 102e43e9..16e9cf89 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -2124,9 +2124,15 @@ bool StructType::canBeUsedExternally(bool _inLibrary) const
// We pass "false" to canBeUsedExternally (_inLibrary), because this struct will be
// passed by value and thus the encoding does not differ, but it will disallow
// mappings.
+ // Also return false if at least one struct member does not have a type.
+ // This might happen, for example, if the type of the member does not exist,
+ // which is reported as an error.
for (auto const& var: m_struct.members())
{
- solAssert(var->annotation().type, "");
+ // If the struct member does not have a type return false.
+ // A TypeError is expected in this case.
+ if (!var->annotation().type)
+ return false;
if (!var->annotation().type->canBeUsedExternally(false))
return false;
}
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 953aa557..0f0548d3 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -374,6 +374,8 @@ public:
Unsigned, Signed
};
+ static IntegerType& uint256() { static std::shared_ptr<IntegerType> uint256(std::make_shared<IntegerType>(256)); return *uint256; }
+
Category category() const override { return Category::Integer; }
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index bd29b382..b02623de 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -558,7 +558,7 @@ string ABIFunctions::abiEncodingFunction(
// special case: convert storage reference type to value type - this is only
// possible for library calls where we just forward the storage reference
solAssert(_encodeAsLibraryTypes, "");
- solAssert(to == IntegerType(256), "");
+ solAssert(to == IntegerType::uint256(), "");
templ("cleanupConvert", "value");
}
else
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 93c8cc77..7d2ad9d2 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -136,7 +136,7 @@ void CompilerUtils::loadFromMemoryDynamic(
void CompilerUtils::storeInMemory(unsigned _offset)
{
- unsigned numBytes = prepareMemoryStore(IntegerType(256), true);
+ unsigned numBytes = prepareMemoryStore(IntegerType::uint256(), true);
if (numBytes > 0)
m_context << u256(_offset) << Instruction::MSTORE;
}
@@ -150,7 +150,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
ref->location() == DataLocation::Memory,
"Only in-memory reference type can be stored."
);
- storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
+ storeInMemoryDynamic(IntegerType::uint256(), _padToWordBoundaries);
}
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
{
@@ -266,7 +266,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
if (calldataType->isDynamicallySized())
{
// put on stack: data_pointer length
- loadFromMemoryDynamic(IntegerType(256), !_fromMemory);
+ loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory);
m_context << Instruction::SWAP1;
// stack: input_end base_offset next_pointer data_offset
m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"});
@@ -277,7 +277,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
{"input_end", "base_offset", "next_ptr", "array_head_ptr"}
);
// retrieve length
- loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true);
+ loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory, true);
// stack: input_end base_offset next_pointer array_length data_pointer
m_context << Instruction::SWAP2;
// stack: input_end base_offset data_pointer array_length next_pointer
@@ -430,7 +430,7 @@ void CompilerUtils::encodeToMemory(
{
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
m_context << u256(strType.value().size());
- storeInMemoryDynamic(IntegerType(256), true);
+ storeInMemoryDynamic(IntegerType::uint256(), true);
// stack: ... <end_of_mem'>
storeInMemoryDynamic(strType, _padToWordBoundaries);
}
@@ -445,7 +445,7 @@ void CompilerUtils::encodeToMemory(
m_context << dupInstruction(1 + arrayType.sizeOnStack());
ArrayUtils(m_context).retrieveLength(arrayType, 1);
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
- storeInMemoryDynamic(IntegerType(256), true);
+ storeInMemoryDynamic(IntegerType::uint256(), true);
// stack: ... <end_of_mem> <value...> <end_of_mem''>
// copy the new memory pointer
m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
@@ -807,7 +807,7 @@ void CompilerUtils::convertType(
allocateMemory();
// stack: mempos
m_context << Instruction::DUP1 << u256(data.size());
- storeInMemoryDynamic(IntegerType(256));
+ storeInMemoryDynamic(IntegerType::uint256());
// stack: mempos datapos
storeStringData(data);
}
@@ -856,7 +856,7 @@ void CompilerUtils::convertType(
if (targetType.isDynamicallySized())
{
m_context << Instruction::DUP2;
- storeInMemoryDynamic(IntegerType(256));
+ storeInMemoryDynamic(IntegerType::uint256());
}
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
if (targetType.baseType()->isValueType())
@@ -1210,7 +1210,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
for (unsigned i = 0; i < _data.size(); i += 32)
{
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
- storeInMemoryDynamic(IntegerType(256));
+ storeInMemoryDynamic(IntegerType::uint256());
}
m_context << Instruction::POP;
}
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index bd8170ad..5f7dce22 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -69,7 +69,7 @@ public:
/// @returns the number of bytes consumed in memory.
unsigned loadFromMemory(
unsigned _offset,
- Type const& _type = IntegerType(256),
+ Type const& _type = IntegerType::uint256(),
bool _fromCalldata = false,
bool _padToWords = false
);
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index c9a1e076..87eecd2e 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -631,7 +631,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.expression().accept(*this);
arguments.front()->accept(*this);
- utils().convertType(*arguments.front()->annotation().type, IntegerType(256), true);
+ utils().convertType(*arguments.front()->annotation().type, IntegerType::uint256(), true);
// Note that function is not the original function, but the ".gas" function.
// Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
@@ -814,13 +814,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::MulMod:
{
arguments[2]->accept(*this);
- utils().convertType(*arguments[2]->annotation().type, IntegerType(256));
+ utils().convertType(*arguments[2]->annotation().type, IntegerType::uint256());
m_context << Instruction::DUP1 << Instruction::ISZERO;
m_context.appendConditionalInvalid();
for (unsigned i = 1; i < 3; i ++)
{
arguments[2 - i]->accept(*this);
- utils().convertType(*arguments[2 - i]->annotation().type, IntegerType(256));
+ utils().convertType(*arguments[2 - i]->annotation().type, IntegerType::uint256());
}
if (function.kind() == FunctionType::Kind::AddMod)
m_context << Instruction::ADDMOD;
@@ -904,7 +904,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// Fetch requested length.
arguments[0]->accept(*this);
- utils().convertType(*arguments[0]->annotation().type, IntegerType(256));
+ utils().convertType(*arguments[0]->annotation().type, IntegerType::uint256());
// Stack: requested_length
utils().fetchFreeMemoryPointer();
@@ -1452,7 +1452,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
TypePointers{keyType}
);
m_context << Instruction::SWAP1;
- utils().storeInMemoryDynamic(IntegerType(256));
+ utils().storeInMemoryDynamic(IntegerType::uint256());
utils().toSizeAfterFreeMemoryPointer();
}
else
@@ -1461,7 +1461,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
m_context << Instruction::SWAP1;
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
- utils().storeInMemoryDynamic(IntegerType(256));
+ utils().storeInMemoryDynamic(IntegerType::uint256());
m_context << u256(0);
}
m_context << Instruction::KECCAK256;
@@ -1474,7 +1474,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_indexAccess.indexExpression()->accept(*this);
- utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType(256), true);
+ utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
// stack layout: <base_ref> [<length>] <index>
ArrayUtils(m_context).accessIndex(arrayType);
switch (arrayType.location())
@@ -1510,7 +1510,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_indexAccess.indexExpression()->accept(*this);
- utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType(256), true);
+ utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
// stack layout: <value> <index>
// check out-of-bounds access
m_context << u256(fixedBytesType.numBytes());
diff --git a/scripts/Dockerfile_alpine b/scripts/Dockerfile_alpine
new file mode 100644
index 00000000..21bba456
--- /dev/null
+++ b/scripts/Dockerfile_alpine
@@ -0,0 +1,5 @@
+FROM alpine
+MAINTAINER chriseth <chris@ethereum.org>
+
+COPY upload/solc-static-linux /usr/local/bin/solc
+ENTRYPOINT ["/usr/local/bin/solc"]
diff --git a/scripts/docker_build.sh b/scripts/docker_build.sh
index 22657a8c..9eedec34 100755
--- a/scripts/docker_build.sh
+++ b/scripts/docker_build.sh
@@ -2,7 +2,11 @@
set -e
+# Scratch image
docker build -t ethereum/solc:build -f scripts/Dockerfile .
tmp_container=$(docker create ethereum/solc:build sh)
mkdir -p upload
docker cp ${tmp_container}:/usr/bin/solc upload/solc-static-linux
+
+# Alpine image
+docker build -t ethereum/solc:build-alpine -f scripts/Dockerfile_alpine .
diff --git a/scripts/docker_deploy.sh b/scripts/docker_deploy.sh
index 00705725..36e918cf 100755
--- a/scripts/docker_deploy.sh
+++ b/scripts/docker_deploy.sh
@@ -2,20 +2,28 @@
set -e
+image="ethereum/solc"
+
+tag_and_push()
+{
+ docker tag "$image:$1" "$image:$2"
+ docker push "$image:$2"
+}
+
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD";
version=$($(dirname "$0")/get_version.sh)
if [ "$TRAVIS_BRANCH" = "develop" ]
then
- docker tag ethereum/solc:build ethereum/solc:nightly;
- docker tag ethereum/solc:build ethereum/solc:nightly-"$version"-"$TRAVIS_COMMIT"
- docker push ethereum/solc:nightly-"$version"-"$TRAVIS_COMMIT";
- docker push ethereum/solc:nightly;
+ tag_and_push build nightly
+ tag_and_push build nightly-"$version"-"$TRAVIS_COMMIT"
+ tag_and_push build-alpine nightly-alpine
+ tag_and_push build-alpine nightly-alpine-"$version"-"$TRAVIS_COMMIT"
elif [ "$TRAVIS_TAG" = v"$version" ]
then
- docker tag ethereum/solc:build ethereum/solc:stable;
- docker tag ethereum/solc:build ethereum/solc:"$version";
- docker push ethereum/solc:stable;
- docker push ethereum/solc:"$version";
+ tag_and_push build stable
+ tag_and_push build "$version"
+ tag_and_push build-alpine stable-alpine
+ tag_and_push build-alpine "$version"-alpine
else
echo "Not publishing docker image from branch $TRAVIS_BRANCH or tag $TRAVIS_TAG"
fi
diff --git a/scripts/docker_deploy_manual.sh b/scripts/docker_deploy_manual.sh
index c098f4ee..0393d22d 100755
--- a/scripts/docker_deploy_manual.sh
+++ b/scripts/docker_deploy_manual.sh
@@ -7,6 +7,7 @@ then
echo "Usage: $0 <tag/branch>"
exit 1
fi
+image="ethereum/solc"
branch="$1"
#docker login
@@ -27,21 +28,27 @@ else
date -u +"nightly.%Y.%-m.%-d" > prerelease.txt
fi
+tag_and_push()
+{
+ docker tag "$image:$1" "$image:$2"
+ docker push "$image:$2"
+}
+
rm -rf .git
-docker build -t ethereum/solc:build -f scripts/Dockerfile .
-tmp_container=$(docker create ethereum/solc:build sh)
+docker build -t "$image":build -f scripts/Dockerfile .
+tmp_container=$(docker create "$image":build sh)
if [ "$branch" = "develop" ]
then
- docker tag ethereum/solc:build ethereum/solc:nightly;
- docker tag ethereum/solc:build ethereum/solc:nightly-"$version"-"$commithash"
- docker push ethereum/solc:nightly-"$version"-"$commithash";
- docker push ethereum/solc:nightly;
+ tag_and_push build nightly
+ tag_and_push build nightly-"$version"-"$commithash"
+ tag_and_push build-alpine nightly-alpine
+ tag_and_push build-alpine nightly-alpine-"$version"-"$commithash"
elif [ "$branch" = v"$version" ]
then
- docker tag ethereum/solc:build ethereum/solc:stable;
- docker tag ethereum/solc:build ethereum/solc:"$version";
- docker push ethereum/solc:stable;
- docker push ethereum/solc:"$version";
+ tag_and_push build stable
+ tag_and_push build "$version"
+ tag_and_push build-alpine stable-alpine
+ tag_and_push build-alpine "$version"-alpine
else
echo "Not publishing docker image from branch or tag $branch"
fi
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index 7f64d8ac..e2baca7f 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -1022,12 +1022,16 @@ void CommandLineInterface::handleAst(string const& _argStr)
map<ASTNode const*, eth::GasMeter::GasConsumption> gasCosts;
for (auto const& contract : m_compiler->contractNames())
{
- auto ret = GasEstimator::breakToStatementLevel(
- GasEstimator(m_evmVersion).structuralEstimation(*m_compiler->runtimeAssemblyItems(contract), asts),
- asts
- );
- for (auto const& it: ret)
- gasCosts[it.first] += it.second;
+ if (auto const* assemblyItems = m_compiler->runtimeAssemblyItems(contract))
+ {
+ auto ret = GasEstimator::breakToStatementLevel(
+ GasEstimator(m_evmVersion).structuralEstimation(*assemblyItems, asts),
+ asts
+ );
+ for (auto const& it: ret)
+ gasCosts[it.first] += it.second;
+ }
+
}
bool legacyFormat = !m_args.count(g_argAstCompactJson);
diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp
index 6e1329a9..e9204cc4 100644
--- a/test/libsolidity/SMTCheckerJSONTest.cpp
+++ b/test/libsolidity/SMTCheckerJSONTest.cpp
@@ -38,11 +38,15 @@ using namespace boost::unit_test;
SMTCheckerTest::SMTCheckerTest(string const& _filename)
: SyntaxTest(_filename)
{
- BOOST_REQUIRE_MESSAGE(boost::algorithm::ends_with(_filename, ".sol"), "Invalid test contract file name: \"" + _filename + "\".");
+ if (!boost::algorithm::ends_with(_filename, ".sol"))
+ BOOST_THROW_EXCEPTION(runtime_error("Invalid test contract file name: \"" + _filename + "\"."));
string jsonFilename = _filename.substr(0, _filename.size() - 4) + ".json";
- BOOST_CHECK(jsonParseFile(jsonFilename, m_smtResponses));
- BOOST_CHECK(m_smtResponses.isObject());
+ if (
+ !jsonParseFile(jsonFilename, m_smtResponses) ||
+ !m_smtResponses.isObject()
+ )
+ BOOST_THROW_EXCEPTION(runtime_error("Invalid JSON file."));
}
bool SMTCheckerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
@@ -59,42 +63,62 @@ bool SMTCheckerTest::run(ostream& _stream, string const& _linePrefix, bool const
// This is the list of responses provided in the test
string auxInput("auxiliaryInput");
- BOOST_CHECK(m_smtResponses.isMember(auxInput));
+ if (!m_smtResponses.isMember(auxInput))
+ BOOST_THROW_EXCEPTION(runtime_error("JSON file does not contain field \"auxiliaryInput\"."));
+
vector<string> inHashes = hashesFromJson(m_smtResponses, auxInput, "smtlib2responses");
// Ensure that the provided list matches the requested one
- BOOST_CHECK_MESSAGE(
- outHashes == inHashes,
- "SMT query hashes differ: " + boost::algorithm::join(outHashes, ", ") + " x " + boost::algorithm::join(inHashes, ", ")
- );
+ if (outHashes != inHashes)
+ BOOST_THROW_EXCEPTION(runtime_error(
+ "SMT query hashes differ: " +
+ boost::algorithm::join(outHashes, ", ") +
+ " x " +
+ boost::algorithm::join(inHashes, ", ")
+ ));
// Rerun the compiler with the provided hashed (2nd run)
input[auxInput] = m_smtResponses[auxInput];
Json::Value endResult = compiler.compile(input);
- BOOST_CHECK(endResult.isMember("errors"));
- Json::Value const& errors = endResult["errors"];
- for (auto const& error: errors)
+ if (endResult.isMember("errors") && endResult["errors"].isArray())
{
- BOOST_CHECK(error.isMember("type") && error["type"].isString());
- BOOST_CHECK(error.isMember("message") && error["message"].isString());
- if (!error.isMember("sourceLocation"))
- continue;
- Json::Value const& location = error["sourceLocation"];
- BOOST_CHECK(location.isMember("start") && location["start"].isInt());
- BOOST_CHECK(location.isMember("end") && location["end"].isInt());
- int start = location["start"].asInt();
- int end = location["end"].asInt();
- if (start >= static_cast<int>(versionPragma.size()))
- start -= versionPragma.size();
- if (end >= static_cast<int>(versionPragma.size()))
- end -= versionPragma.size();
- m_errorList.emplace_back(SyntaxTestError{
- error["type"].asString(),
- error["message"].asString(),
- start,
- end
- });
+ Json::Value const& errors = endResult["errors"];
+ for (auto const& error: errors)
+ {
+ if (
+ !error.isMember("type") ||
+ !error["type"].isString()
+ )
+ BOOST_THROW_EXCEPTION(runtime_error("Error must have a type."));
+ if (
+ !error.isMember("message") ||
+ !error["message"].isString()
+ )
+ BOOST_THROW_EXCEPTION(runtime_error("Error must have a message."));
+ if (!error.isMember("sourceLocation"))
+ continue;
+ Json::Value const& location = error["sourceLocation"];
+ if (
+ !location.isMember("start") ||
+ !location["start"].isInt() ||
+ !location.isMember("end") ||
+ !location["end"].isInt()
+ )
+ BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end."));
+ int start = location["start"].asInt();
+ int end = location["end"].asInt();
+ if (start >= static_cast<int>(versionPragma.size()))
+ start -= versionPragma.size();
+ if (end >= static_cast<int>(versionPragma.size()))
+ end -= versionPragma.size();
+ m_errorList.emplace_back(SyntaxTestError{
+ error["type"].asString(),
+ error["message"].asString(),
+ start,
+ end
+ });
+ }
}
return printExpectationAndError(_stream, _linePrefix, _formatted);
@@ -123,6 +147,7 @@ Json::Value SMTCheckerTest::buildJson(string const& _extra)
string sources = " \"sources\": { " + sourceName + ": " + sourceObj + "}";
string input = "{" + language + ", " + sources + "}";
Json::Value source;
- BOOST_REQUIRE(jsonParse(input, source));
+ if (!jsonParse(input, source))
+ BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string."));
return source;
}
diff --git a/test/libsolidity/syntaxTests/functionTypes/function_type_struct.sol b/test/libsolidity/syntaxTests/functionTypes/function_type_struct.sol
new file mode 100644
index 00000000..a367996e
--- /dev/null
+++ b/test/libsolidity/syntaxTests/functionTypes/function_type_struct.sol
@@ -0,0 +1,8 @@
+library L
+{
+ struct Nested
+ {
+ uint y;
+ }
+ function f(function(Nested memory) external) external pure {}
+}
diff --git a/test/libsolidity/syntaxTests/functionTypes/function_type_struct_undefined_member.sol b/test/libsolidity/syntaxTests/functionTypes/function_type_struct_undefined_member.sol
new file mode 100644
index 00000000..ca08afe5
--- /dev/null
+++ b/test/libsolidity/syntaxTests/functionTypes/function_type_struct_undefined_member.sol
@@ -0,0 +1,11 @@
+library L
+{
+ struct Nested
+ {
+ Non y;
+ }
+ function f(function(Nested memory) external) external pure {}
+}
+// ----
+// DeclarationError: (32-35): Identifier not found or not unique.
+// TypeError: (63-76): Internal type cannot be used for external function type.
diff --git a/test/libsolidity/syntaxTests/getter/complex_struct.sol b/test/libsolidity/syntaxTests/getter/complex_struct.sol
new file mode 100644
index 00000000..3fa8111c
--- /dev/null
+++ b/test/libsolidity/syntaxTests/getter/complex_struct.sol
@@ -0,0 +1,7 @@
+contract C {
+ struct Y {
+ uint a;
+ uint b;
+ }
+ mapping(uint256 => Y) public m;
+}
diff --git a/test/libsolidity/syntaxTests/getter/nested_structs.sol b/test/libsolidity/syntaxTests/getter/nested_structs.sol
new file mode 100644
index 00000000..1068f287
--- /dev/null
+++ b/test/libsolidity/syntaxTests/getter/nested_structs.sol
@@ -0,0 +1,11 @@
+contract C {
+ struct Y {
+ uint b;
+ }
+ struct X {
+ Y a;
+ }
+ mapping(uint256 => X) public m;
+}
+// ----
+// TypeError: (88-118): The following types are only supported for getters in the new experimental ABI encoder: struct C.Y memory. Either remove "public" or use "pragma experimental ABIEncoderV2;" to enable the feature.
diff --git a/test/libsolidity/syntaxTests/getter/recursive_struct.sol b/test/libsolidity/syntaxTests/getter/recursive_struct.sol
new file mode 100644
index 00000000..d81cac60
--- /dev/null
+++ b/test/libsolidity/syntaxTests/getter/recursive_struct.sol
@@ -0,0 +1,8 @@
+contract C {
+ struct Y {
+ Y[] x;
+ }
+ mapping(uint256 => Y) public m;
+}
+// ----
+// TypeError: (53-83): Internal or recursive type is not allowed for public state variables.
diff --git a/test/libsolidity/syntaxTests/getter/simple_struct.sol b/test/libsolidity/syntaxTests/getter/simple_struct.sol
new file mode 100644
index 00000000..c7a23ae9
--- /dev/null
+++ b/test/libsolidity/syntaxTests/getter/simple_struct.sol
@@ -0,0 +1,6 @@
+contract C {
+ struct Y {
+ uint b;
+ }
+ mapping(uint256 => Y) public m;
+}