mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2710 from ethereum/develop
Merge develop into release for 0.4.15
This commit is contained in:
commit
bbb8e64fbe
@ -8,7 +8,7 @@ include(EthPolicy)
|
||||
eth_policy()
|
||||
|
||||
# project name and version should be set after cmake_policy CMP0048
|
||||
set(PROJECT_VERSION "0.4.14")
|
||||
set(PROJECT_VERSION "0.4.15")
|
||||
project(solidity VERSION ${PROJECT_VERSION})
|
||||
|
||||
# Let's find our dependencies
|
||||
|
13
Changelog.md
13
Changelog.md
@ -1,3 +1,16 @@
|
||||
### 0.4.15 (2017-08-08)
|
||||
|
||||
Features:
|
||||
* Type Checker: Show unimplemented function if trying to instantiate an abstract class.
|
||||
|
||||
Bugfixes:
|
||||
* Code Generator: ``.delegatecall()`` should always return execution outcome.
|
||||
* Code Generator: Provide "new account gas" for low-level ``callcode`` and ``delegatecall``.
|
||||
* Type Checker: Constructors must be implemented if declared.
|
||||
* Type Checker: Disallow the ``.gas()`` modifier on ``ecrecover``, ``sha256`` and ``ripemd160``.
|
||||
* Type Checker: Do not mark overloaded functions as shadowing other functions.
|
||||
* Type Checker: Internal library functions must be implemented if declared.
|
||||
|
||||
### 0.4.14 (2017-07-31)
|
||||
|
||||
Features:
|
||||
|
@ -1,4 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "DelegateCallReturnValue",
|
||||
"summary": "The low-level .delegatecall() does not return the execution outcome, but converts the value returned by the functioned called to a boolean instead.",
|
||||
"description": "The return value of the low-level .delegatecall() function is taken from a position in memory, where the call data or the return data resides. This value is interpreted as a boolean and put onto the stack. This means if the called function returns at least 32 zero bytes, .delegatecall() returns false even if the call was successuful.",
|
||||
"introduced": "0.3.0",
|
||||
"fixed": "0.4.15",
|
||||
"severity": "low"
|
||||
},
|
||||
{
|
||||
"name": "ECRecoverMalformedInput",
|
||||
"summary": "The ecrecover() builtin can return garbage for malformed input.",
|
||||
|
@ -182,6 +182,7 @@
|
||||
},
|
||||
"0.3.0": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -198,6 +199,7 @@
|
||||
},
|
||||
"0.3.1": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -213,6 +215,7 @@
|
||||
},
|
||||
"0.3.2": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -228,6 +231,7 @@
|
||||
},
|
||||
"0.3.3": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -242,6 +246,7 @@
|
||||
},
|
||||
"0.3.4": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -256,6 +261,7 @@
|
||||
},
|
||||
"0.3.5": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -270,6 +276,7 @@
|
||||
},
|
||||
"0.3.6": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -282,6 +289,7 @@
|
||||
},
|
||||
"0.4.0": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -294,6 +302,7 @@
|
||||
},
|
||||
"0.4.1": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -306,6 +315,7 @@
|
||||
},
|
||||
"0.4.10": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction"
|
||||
@ -314,6 +324,7 @@
|
||||
},
|
||||
"0.4.11": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral"
|
||||
],
|
||||
@ -321,22 +332,31 @@
|
||||
},
|
||||
"0.4.12": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput"
|
||||
],
|
||||
"released": "2017-07-03"
|
||||
},
|
||||
"0.4.13": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput"
|
||||
],
|
||||
"released": "2017-07-06"
|
||||
},
|
||||
"0.4.14": {
|
||||
"bugs": [],
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue"
|
||||
],
|
||||
"released": "2017-07-31"
|
||||
},
|
||||
"0.4.15": {
|
||||
"bugs": [],
|
||||
"released": "2017-08-08"
|
||||
},
|
||||
"0.4.2": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -348,6 +368,7 @@
|
||||
},
|
||||
"0.4.3": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -358,6 +379,7 @@
|
||||
},
|
||||
"0.4.4": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -367,6 +389,7 @@
|
||||
},
|
||||
"0.4.5": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -377,6 +400,7 @@
|
||||
},
|
||||
"0.4.6": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction",
|
||||
@ -386,6 +410,7 @@
|
||||
},
|
||||
"0.4.7": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction"
|
||||
@ -394,6 +419,7 @@
|
||||
},
|
||||
"0.4.8": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction"
|
||||
@ -402,6 +428,7 @@
|
||||
},
|
||||
"0.4.9": {
|
||||
"bugs": [
|
||||
"DelegateCallReturnValue",
|
||||
"ECRecoverMalformedInput",
|
||||
"SkipEmptyStringLiteral",
|
||||
"ConstantOptimizerSubtraction"
|
||||
|
@ -393,6 +393,9 @@ When exceptions happen in a sub-call, they "bubble up" (i.e. exceptions are reth
|
||||
and the low-level functions ``call``, ``delegatecall`` and ``callcode`` -- those return ``false`` in case
|
||||
of an exception instead of "bubbling up".
|
||||
|
||||
.. warning::
|
||||
The low-level ``call``, ``delegatecall`` and ``callcode`` will return success if the calling account is non-existent, as part of the design of EVM. Existence must be checked prior to calling if desired.
|
||||
|
||||
Catching exceptions is not yet possible.
|
||||
|
||||
In the following example, you can see how ``require`` can be used to easily check conditions on inputs
|
||||
|
@ -56,7 +56,7 @@ repository contains potentially unstable changes in the develop branch.
|
||||
|
||||
docker run ethereum/solc:stable solc --version
|
||||
|
||||
Currenty, the docker image only contains the compiler executable,
|
||||
Currently, the docker image only contains the compiler executable,
|
||||
so you have to do some additional work to link in the source and
|
||||
output directories.
|
||||
|
||||
@ -83,7 +83,15 @@ If you want to use the cutting edge developer version:
|
||||
sudo apt-get update
|
||||
sudo apt-get install solc
|
||||
|
||||
We are also releasing a `snap package <https://snapcraft.io/>`_, which is installable in all the `supported Linux distros <https://snapcraft.io/docs/core/install>`_. To help testing the unstable solc with the most recent changes from the development branch:
|
||||
We are also releasing a `snap package <https://snapcraft.io/>`_, which is installable in all the `supported Linux distros <https://snapcraft.io/docs/core/install>`_. To install the latest stable version of solc:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
sudo snap install solc
|
||||
|
||||
Or if you want to help testing the unstable solc with the most recent changes from the development branch:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
sudo snap install solc --edge
|
||||
|
||||
|
@ -277,9 +277,9 @@ activate themselves.
|
||||
if (highestBidder != 0) {
|
||||
// Sending back the money by simply using
|
||||
// highestBidder.send(highestBid) is a security risk
|
||||
// because it can be prevented by the caller by e.g.
|
||||
// raising the call stack to 1023. It is always safer
|
||||
// to let the recipients withdraw their money themselves.
|
||||
// because it could execute an untrusted contract.
|
||||
// It is always safer to let the recipients
|
||||
// withdraw their money themselves.
|
||||
pendingReturns[highestBidder] += highestBid;
|
||||
}
|
||||
highestBidder = msg.sender;
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
bool registerDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr, bool _invisible = false, bool _update = false);
|
||||
std::vector<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
|
||||
ASTNode const* enclosingNode() const { return m_enclosingNode; }
|
||||
DeclarationContainer const* enclosingContainer() const { return m_enclosingContainer; }
|
||||
std::map<ASTString, std::vector<Declaration const*>> const& declarations() const { return m_declarations; }
|
||||
/// @returns whether declaration is valid, and if not also returns previous declaration.
|
||||
Declaration const* conflictingDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr) const;
|
||||
|
@ -452,13 +452,9 @@ bool DeclarationRegistrationHelper::registerDeclaration(
|
||||
_errorLocation = &_declaration.location();
|
||||
|
||||
Declaration const* shadowedDeclaration = nullptr;
|
||||
if (_warnOnShadow && !_declaration.name().empty())
|
||||
for (auto const* decl: _container.resolveName(_declaration.name(), true))
|
||||
if (decl != &_declaration)
|
||||
{
|
||||
if (_warnOnShadow && !_declaration.name().empty() && _container.enclosingContainer())
|
||||
for (auto const* decl: _container.enclosingContainer()->resolveName(_declaration.name(), true))
|
||||
shadowedDeclaration = decl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_container.registerDeclaration(_declaration, _name, !_declaration.isVisibleInContract()))
|
||||
{
|
||||
|
@ -169,6 +169,8 @@ private:
|
||||
void closeCurrentScope();
|
||||
void registerDeclaration(Declaration& _declaration, bool _opensScope);
|
||||
|
||||
static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2);
|
||||
|
||||
/// @returns the canonical name of the current scope.
|
||||
std::string currentCanonicalName() const;
|
||||
|
||||
|
@ -112,8 +112,6 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
m_errorReporter.typeError(fallbackFunction->returnParameterList()->location(), "Fallback function cannot return values.");
|
||||
}
|
||||
}
|
||||
if (!function->isImplemented())
|
||||
_contract.annotation().isFullyImplemented = false;
|
||||
}
|
||||
|
||||
for (auto const& n: _contract.subNodes())
|
||||
@ -188,20 +186,13 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
|
||||
using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
|
||||
map<string, vector<FunTypeAndFlag>> functions;
|
||||
|
||||
bool allBaseConstructorsImplemented = true;
|
||||
// Search from base to derived
|
||||
for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
|
||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||
{
|
||||
// Take constructors out of overload hierarchy
|
||||
if (function->isConstructor())
|
||||
{
|
||||
if (!function->isImplemented())
|
||||
// Base contract's constructor is not fully implemented, no way to get
|
||||
// out of this.
|
||||
allBaseConstructorsImplemented = false;
|
||||
continue;
|
||||
}
|
||||
auto& overloads = functions[function->name()];
|
||||
FunctionTypePointer funType = make_shared<FunctionType>(*function);
|
||||
auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
|
||||
@ -219,16 +210,15 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
|
||||
it->second = true;
|
||||
}
|
||||
|
||||
if (!allBaseConstructorsImplemented)
|
||||
_contract.annotation().isFullyImplemented = false;
|
||||
|
||||
// Set to not fully implemented if at least one flag is false.
|
||||
for (auto const& it: functions)
|
||||
for (auto const& funAndFlag: it.second)
|
||||
if (!funAndFlag.second)
|
||||
{
|
||||
_contract.annotation().isFullyImplemented = false;
|
||||
return;
|
||||
FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(&funAndFlag.first->declaration());
|
||||
solAssert(function, "");
|
||||
_contract.annotation().unimplementedFunctions.push_back(function);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +256,8 @@ void TypeChecker::checkContractAbstractConstructors(ContractDefinition const& _c
|
||||
}
|
||||
}
|
||||
if (!argumentsNeeded.empty())
|
||||
_contract.annotation().isFullyImplemented = false;
|
||||
for (ContractDefinition const* contract: argumentsNeeded)
|
||||
_contract.annotation().unimplementedFunctions.push_back(contract->constructor());
|
||||
}
|
||||
|
||||
void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contract)
|
||||
@ -525,6 +516,10 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
}
|
||||
if (_function.isImplemented())
|
||||
_function.body().accept(*this);
|
||||
else if (_function.isConstructor())
|
||||
m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared.");
|
||||
else if (isLibraryFunction && _function.visibility() <= FunctionDefinition::Visibility::Internal)
|
||||
m_errorReporter.typeError(_function.location(), "Internal library function must be implemented if declared.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1050,7 +1045,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
||||
{
|
||||
auto kind = callType->kind();
|
||||
if (
|
||||
kind == FunctionType::Kind::Bare ||
|
||||
kind == FunctionType::Kind::BareCall ||
|
||||
kind == FunctionType::Kind::BareCallCode ||
|
||||
kind == FunctionType::Kind::BareDelegateCall
|
||||
)
|
||||
@ -1523,8 +1518,15 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
|
||||
if (!contract)
|
||||
m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
|
||||
if (!contract->annotation().isFullyImplemented)
|
||||
m_errorReporter.typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
|
||||
if (!contract->annotation().unimplementedFunctions.empty())
|
||||
m_errorReporter.typeError(
|
||||
_newExpression.location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Missing implementation:",
|
||||
contract->annotation().unimplementedFunctions.front()->location()
|
||||
),
|
||||
"Trying to create an instance of an abstract contract."
|
||||
);
|
||||
if (!contract->constructorIsPublic())
|
||||
m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly.");
|
||||
|
||||
|
@ -79,8 +79,8 @@ struct TypeDeclarationAnnotation: ASTAnnotation
|
||||
|
||||
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnotation
|
||||
{
|
||||
/// Whether all functions are implemented.
|
||||
bool isFullyImplemented = true;
|
||||
/// List of functions without a body. Can also contain functions from base classes.
|
||||
std::vector<FunctionDefinition const*> unimplementedFunctions;
|
||||
/// List of all (direct and indirect) base contracts in order from derived to
|
||||
/// base, including the contract itself.
|
||||
std::vector<ContractDefinition const*> linearizedBaseContracts;
|
||||
|
@ -253,7 +253,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node)
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("contractKind", contractKind(_node.contractKind())),
|
||||
make_pair("fullyImplemented", _node.annotation().isFullyImplemented),
|
||||
make_pair("fullyImplemented", _node.annotation().unimplementedFunctions.empty()),
|
||||
make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)),
|
||||
make_pair("baseContracts", toJson(_node.baseContracts())),
|
||||
make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies)),
|
||||
|
@ -477,7 +477,7 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
|
||||
if (isAddress())
|
||||
return {
|
||||
{"balance", make_shared<IntegerType >(256)},
|
||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::Bare, true, false, true)},
|
||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, false, true)},
|
||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, false, true)},
|
||||
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
|
||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
||||
@ -2178,7 +2178,7 @@ string FunctionType::identifier() const
|
||||
case Kind::External: id += "external"; break;
|
||||
case Kind::CallCode: id += "callcode"; break;
|
||||
case Kind::DelegateCall: id += "delegatecall"; break;
|
||||
case Kind::Bare: id += "bare"; break;
|
||||
case Kind::BareCall: id += "barecall"; break;
|
||||
case Kind::BareCallCode: id += "barecallcode"; break;
|
||||
case Kind::BareDelegateCall: id += "baredelegatecall"; break;
|
||||
case Kind::Creation: id += "creation"; break;
|
||||
@ -2346,7 +2346,7 @@ unsigned FunctionType::sizeOnStack() const
|
||||
unsigned size = 0;
|
||||
if (kind == Kind::External || kind == Kind::CallCode || kind == Kind::DelegateCall)
|
||||
size = 2;
|
||||
else if (kind == Kind::Bare || kind == Kind::BareCallCode || kind == Kind::BareDelegateCall)
|
||||
else if (kind == Kind::BareCall || kind == Kind::BareCallCode || kind == Kind::BareDelegateCall)
|
||||
size = 1;
|
||||
else if (kind == Kind::Internal)
|
||||
size = 1;
|
||||
@ -2402,10 +2402,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
||||
{
|
||||
case Kind::External:
|
||||
case Kind::Creation:
|
||||
case Kind::ECRecover:
|
||||
case Kind::SHA256:
|
||||
case Kind::RIPEMD160:
|
||||
case Kind::Bare:
|
||||
case Kind::BareCall:
|
||||
case Kind::BareCallCode:
|
||||
case Kind::BareDelegateCall:
|
||||
{
|
||||
@ -2509,7 +2506,7 @@ bool FunctionType::isBareCall() const
|
||||
{
|
||||
switch (m_kind)
|
||||
{
|
||||
case Kind::Bare:
|
||||
case Kind::BareCall:
|
||||
case Kind::BareCallCode:
|
||||
case Kind::BareDelegateCall:
|
||||
case Kind::ECRecover:
|
||||
|
@ -838,7 +838,7 @@ public:
|
||||
External, ///< external call using CALL
|
||||
CallCode, ///< external call using CALLCODE, i.e. not exchanging the storage
|
||||
DelegateCall, ///< external call using DELEGATECALL, i.e. not exchanging the storage
|
||||
Bare, ///< CALL without function hash
|
||||
BareCall, ///< CALL without function hash
|
||||
BareCallCode, ///< CALLCODE without function hash
|
||||
BareDelegateCall, ///< DELEGATECALL without function hash
|
||||
Creation, ///< external call using CREATE
|
||||
|
@ -546,7 +546,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::External:
|
||||
case FunctionType::Kind::CallCode:
|
||||
case FunctionType::Kind::DelegateCall:
|
||||
case FunctionType::Kind::Bare:
|
||||
case FunctionType::Kind::BareCall:
|
||||
case FunctionType::Kind::BareCallCode:
|
||||
case FunctionType::Kind::BareDelegateCall:
|
||||
_functionCall.expression().accept(*this);
|
||||
@ -642,7 +642,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
TypePointers{},
|
||||
strings(),
|
||||
strings(),
|
||||
FunctionType::Kind::Bare,
|
||||
FunctionType::Kind::BareCall,
|
||||
false,
|
||||
nullptr,
|
||||
false,
|
||||
@ -973,7 +973,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
case FunctionType::Kind::DelegateCall:
|
||||
case FunctionType::Kind::CallCode:
|
||||
case FunctionType::Kind::Send:
|
||||
case FunctionType::Kind::Bare:
|
||||
case FunctionType::Kind::BareCall:
|
||||
case FunctionType::Kind::BareCallCode:
|
||||
case FunctionType::Kind::BareDelegateCall:
|
||||
case FunctionType::Kind::Transfer:
|
||||
@ -1560,7 +1560,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
|
||||
|
||||
auto funKind = _functionType.kind();
|
||||
bool returnSuccessCondition = funKind == FunctionType::Kind::Bare || funKind == FunctionType::Kind::BareCallCode;
|
||||
bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall;
|
||||
bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode;
|
||||
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
|
||||
|
||||
@ -1579,7 +1579,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
TypePointers parameterTypes = _functionType.parameterTypes();
|
||||
bool manualFunctionId = false;
|
||||
if (
|
||||
(funKind == FunctionType::Kind::Bare || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall) &&
|
||||
(funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall) &&
|
||||
!_arguments.empty()
|
||||
)
|
||||
{
|
||||
@ -1712,7 +1712,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
u256 gasNeededByCaller = eth::GasCosts::callGas + 10;
|
||||
if (_functionType.valueSet())
|
||||
gasNeededByCaller += eth::GasCosts::callValueTransferGas;
|
||||
if (!isCallCode && !isDelegateCall && !existenceChecked)
|
||||
if (!existenceChecked)
|
||||
gasNeededByCaller += eth::GasCosts::callNewAccountGas; // we never know
|
||||
m_context << gasNeededByCaller << Instruction::GAS << Instruction::SUB;
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ void CompilerStack::compileContract(
|
||||
{
|
||||
if (
|
||||
_compiledContracts.count(&_contract) ||
|
||||
!_contract.annotation().isFullyImplemented ||
|
||||
!_contract.annotation().unimplementedFunctions.empty() ||
|
||||
!_contract.constructorIsPublic()
|
||||
)
|
||||
return;
|
||||
|
@ -151,6 +151,16 @@ void ErrorReporter::syntaxError(SourceLocation const& _location, string const& _
|
||||
);
|
||||
}
|
||||
|
||||
void ErrorReporter::typeError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description)
|
||||
{
|
||||
error(
|
||||
Error::Type::TypeError,
|
||||
_location,
|
||||
_secondaryLocation,
|
||||
_description
|
||||
);
|
||||
}
|
||||
|
||||
void ErrorReporter::typeError(SourceLocation const& _location, string const& _description)
|
||||
{
|
||||
error(
|
||||
|
@ -73,6 +73,12 @@ public:
|
||||
|
||||
void syntaxError(SourceLocation const& _location, std::string const& _description);
|
||||
|
||||
void typeError(
|
||||
SourceLocation const& _location,
|
||||
SecondarySourceLocation const& _secondaryLocation,
|
||||
std::string const& _description
|
||||
);
|
||||
|
||||
void typeError(SourceLocation const& _location, std::string const& _description);
|
||||
|
||||
void fatalTypeError(SourceLocation const& _location, std::string const& _description);
|
||||
|
@ -101,6 +101,8 @@ void SourceReferenceFormatter::printExceptionInformation(
|
||||
_stream << _name;
|
||||
if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
|
||||
_stream << ": " << *description << endl;
|
||||
else
|
||||
_stream << endl;
|
||||
|
||||
printSourceLocation(_stream, location, _scannerFromSourceName);
|
||||
|
||||
@ -108,9 +110,8 @@ void SourceReferenceFormatter::printExceptionInformation(
|
||||
{
|
||||
for (auto info: secondarylocation->infos)
|
||||
{
|
||||
_stream << info.first << " ";
|
||||
printSourceName(_stream, &info.second, _scannerFromSourceName);
|
||||
_stream << endl;
|
||||
_stream << info.first << endl;
|
||||
printSourceLocation(_stream, &info.second, _scannerFromSourceName);
|
||||
}
|
||||
_stream << endl;
|
||||
|
@ -1950,6 +1950,87 @@ BOOST_AUTO_TEST_CASE(ripemd)
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(-1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(packed_keccak256)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function a(bytes32 input) returns (bytes32 hash) {
|
||||
var b = 65536;
|
||||
uint c = 256;
|
||||
return keccak256(8, input, b, input, c);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
auto f = [&](u256 const& _x) -> u256
|
||||
{
|
||||
return dev::keccak256(
|
||||
toCompactBigEndian(unsigned(8)) +
|
||||
toBigEndian(_x) +
|
||||
toCompactBigEndian(unsigned(65536)) +
|
||||
toBigEndian(_x) +
|
||||
toBigEndian(u256(256))
|
||||
);
|
||||
};
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(4));
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(5));
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(-1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(packed_sha256)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function a(bytes32 input) returns (bytes32 hash) {
|
||||
var b = 65536;
|
||||
uint c = 256;
|
||||
return sha256(8, input, b, input, c);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
auto f = [&](u256 const& _x) -> bytes
|
||||
{
|
||||
if (_x == u256(4))
|
||||
return fromHex("804e0d7003cfd70fc925dc103174d9f898ebb142ecc2a286da1abd22ac2ce3ac");
|
||||
if (_x == u256(5))
|
||||
return fromHex("e94921945f9068726c529a290a954f412bcac53184bb41224208a31edbf63cf0");
|
||||
if (_x == u256(-1))
|
||||
return fromHex("f14def4d07cd185ddd8b10a81b2238326196a38867e6e6adbcc956dc913488c7");
|
||||
return fromHex("");
|
||||
};
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(4));
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(5));
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(-1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(packed_ripemd160)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function a(bytes32 input) returns (bytes32 hash) {
|
||||
var b = 65536;
|
||||
uint c = 256;
|
||||
return ripemd160(8, input, b, input, c);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
auto f = [&](u256 const& _x) -> bytes
|
||||
{
|
||||
if (_x == u256(4))
|
||||
return fromHex("f93175303eba2a7b372174fc9330237f5ad202fc000000000000000000000000");
|
||||
if (_x == u256(5))
|
||||
return fromHex("04f4fc112e2bfbe0d38f896a46629e08e2fcfad5000000000000000000000000");
|
||||
if (_x == u256(-1))
|
||||
return fromHex("c0a2e4b1f3ff766a9a0089e7a410391730872495000000000000000000000000");
|
||||
return fromHex("");
|
||||
};
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(4));
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(5));
|
||||
testContractAgainstCpp("a(bytes32)", f, u256(-1));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ecrecover)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
@ -2318,21 +2399,6 @@ BOOST_AUTO_TEST_CASE(gas_and_value_basic)
|
||||
BOOST_REQUIRE(callContractFunction("checkState()") == encodeArgs(false, 20 - 5));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(gas_for_builtin)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract Contract {
|
||||
function test(uint g) returns (bytes32 data, bool flag) {
|
||||
data = ripemd160.gas(g)("abc");
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_CHECK(callContractFunction("test(uint256)", 500) == bytes());
|
||||
BOOST_CHECK(callContractFunction("test(uint256)", 800) == encodeArgs(u256("0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc000000000000000000000000"), true));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(value_complex)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
@ -9816,6 +9882,64 @@ BOOST_AUTO_TEST_CASE(inlineasm_empty_let)
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0), u256(0)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(bare_call_invalid_address)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
/// Calling into non-existant account is successful (creates the account)
|
||||
function f() external constant returns (bool) {
|
||||
return address(0x4242).call();
|
||||
}
|
||||
function g() external constant returns (bool) {
|
||||
return address(0x4242).callcode();
|
||||
}
|
||||
function h() external constant returns (bool) {
|
||||
return address(0x4242).delegatecall();
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
|
||||
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
|
||||
BOOST_CHECK(callContractFunction("h()") == encodeArgs(u256(1)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(delegatecall_return_value)
|
||||
{
|
||||
char const* sourceCode = R"DELIMITER(
|
||||
contract C {
|
||||
uint value;
|
||||
function set(uint _value) external {
|
||||
value = _value;
|
||||
}
|
||||
function get() external constant returns (uint) {
|
||||
return value;
|
||||
}
|
||||
function get_delegated() external constant returns (bool) {
|
||||
return this.delegatecall(bytes4(sha3("get()")));
|
||||
}
|
||||
function assert0() external constant {
|
||||
assert(value == 0);
|
||||
}
|
||||
function assert0_delegated() external constant returns (bool) {
|
||||
return this.delegatecall(bytes4(sha3("assert0()")));
|
||||
}
|
||||
}
|
||||
)DELIMITER";
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0)));
|
||||
BOOST_CHECK(callContractFunction("assert0_delegated()") == encodeArgs(u256(1)));
|
||||
BOOST_CHECK(callContractFunction("get_delegated()") == encodeArgs(u256(1)));
|
||||
BOOST_CHECK(callContractFunction("set(uint256)", u256(1)) == encodeArgs());
|
||||
BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(1)));
|
||||
BOOST_CHECK(callContractFunction("assert0_delegated()") == encodeArgs(u256(0)));
|
||||
BOOST_CHECK(callContractFunction("get_delegated()") == encodeArgs(u256(1)));
|
||||
BOOST_CHECK(callContractFunction("set(uint256)", u256(42)) == encodeArgs());
|
||||
BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(42)));
|
||||
BOOST_CHECK(callContractFunction("assert0_delegated()") == encodeArgs(u256(0)));
|
||||
BOOST_CHECK(callContractFunction("get_delegated()") == encodeArgs(u256(1)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -624,7 +624,7 @@ BOOST_AUTO_TEST_CASE(function_no_implementation)
|
||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||
BOOST_REQUIRE(contract);
|
||||
BOOST_CHECK(!contract->annotation().isFullyImplemented);
|
||||
BOOST_CHECK(!contract->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(!contract->definedFunctions()[0]->isImplemented());
|
||||
}
|
||||
|
||||
@ -640,10 +640,10 @@ BOOST_AUTO_TEST_CASE(abstract_contract)
|
||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||
BOOST_REQUIRE(base);
|
||||
BOOST_CHECK(!base->annotation().isFullyImplemented);
|
||||
BOOST_CHECK(!base->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(!base->definedFunctions()[0]->isImplemented());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(derived->annotation().isFullyImplemented);
|
||||
BOOST_CHECK(derived->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(derived->definedFunctions()[0]->isImplemented());
|
||||
}
|
||||
|
||||
@ -659,9 +659,9 @@ BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
|
||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||
BOOST_REQUIRE(base);
|
||||
BOOST_CHECK(!base->annotation().isFullyImplemented);
|
||||
BOOST_CHECK(!base->annotation().unimplementedFunctions.empty());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(!derived->annotation().isFullyImplemented);
|
||||
BOOST_CHECK(!derived->annotation().unimplementedFunctions.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_abstract_contract)
|
||||
@ -677,44 +677,6 @@ BOOST_AUTO_TEST_CASE(create_abstract_contract)
|
||||
CHECK_ERROR(text, TypeError, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
char const* text = R"(
|
||||
contract BaseBase { function BaseBase(uint j); }
|
||||
contract base is BaseBase { function foo(); }
|
||||
contract derived is base {
|
||||
function derived(uint i) BaseBase(i){}
|
||||
function foo() {}
|
||||
}
|
||||
)";
|
||||
ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name resolving failed");
|
||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||
BOOST_CHECK_EQUAL(nodes.size(), 4);
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[3].get());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(!derived->annotation().isFullyImplemented);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
char const* text = R"(
|
||||
contract BaseBase { function BaseBase(uint); }
|
||||
contract base is BaseBase { function foo(); }
|
||||
contract derived is base {
|
||||
function derived(uint) {}
|
||||
function foo() {}
|
||||
}
|
||||
)";
|
||||
ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name resolving failed");
|
||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||
BOOST_CHECK_EQUAL(nodes.size(), 4);
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[3].get());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(!derived->annotation().isFullyImplemented);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
@ -738,7 +700,7 @@ BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
||||
BOOST_CHECK_EQUAL(nodes.size(), 3);
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(!derived->annotation().isFullyImplemented);
|
||||
BOOST_CHECK(!derived->annotation().unimplementedFunctions.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
||||
@ -5714,7 +5676,7 @@ BOOST_AUTO_TEST_CASE(interface_constructor)
|
||||
function I();
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Constructor cannot be defined in interfaces");
|
||||
CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Constructor cannot be defined in interfaces");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(interface_functions)
|
||||
@ -6134,6 +6096,25 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_with_variables)
|
||||
CHECK_WARNING(text, "shadows a builtin symbol");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(shadowing_builtins_with_storage_variables)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
uint msg;
|
||||
}
|
||||
)";
|
||||
CHECK_WARNING(text, "shadows a builtin symbol");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(shadowing_builtin_at_global_scope)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract msg {
|
||||
}
|
||||
)";
|
||||
CHECK_WARNING(text, "shadows a builtin symbol");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(shadowing_builtins_with_parameters)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -6190,6 +6171,28 @@ BOOST_AUTO_TEST_CASE(shadowing_builtins_ignores_constructor)
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_overload_is_not_shadowing)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function f() {}
|
||||
function f(uint) {}
|
||||
}
|
||||
)";
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_override_is_not_shadowing)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract D { function f() {} }
|
||||
contract C is D {
|
||||
function f(uint) {}
|
||||
}
|
||||
)";
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(callable_crash)
|
||||
{
|
||||
char const* text = R"(
|
||||
@ -6437,7 +6440,7 @@ BOOST_AUTO_TEST_CASE(using_this_in_constructor)
|
||||
CHECK_WARNING(text, "\"this\" used in constructor");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(do_not_crash_on_not_lalue)
|
||||
BOOST_AUTO_TEST_CASE(do_not_crash_on_not_lvalue)
|
||||
{
|
||||
// This checks for a bug that caused a crash because of continued analysis.
|
||||
char const* text = R"(
|
||||
@ -6451,6 +6454,110 @@ BOOST_AUTO_TEST_CASE(do_not_crash_on_not_lalue)
|
||||
CHECK_ERROR_ALLOW_MULTI(text, TypeError, "is not callable");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(builtin_reject_gas)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
keccak256.gas();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"gas\" not found or not visible after argument-dependent lookup");
|
||||
text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
sha256.gas();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"gas\" not found or not visible after argument-dependent lookup");
|
||||
text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
ripemd160.gas();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"gas\" not found or not visible after argument-dependent lookup");
|
||||
text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
ecrecover.gas();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"gas\" not found or not visible after argument-dependent lookup");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(builtin_reject_value)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
keccak256.value();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup");
|
||||
text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
sha256.value();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup");
|
||||
text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
ripemd160.value();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup");
|
||||
text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
ecrecover.value();
|
||||
}
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constructor_without_implementation)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function C();
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Constructor must be implemented if declared.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(library_function_without_implementation)
|
||||
{
|
||||
char const* text = R"(
|
||||
library L {
|
||||
function f();
|
||||
}
|
||||
)";
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
text = R"(
|
||||
library L {
|
||||
function f() internal;
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Internal library function must be implemented if declared.");
|
||||
text = R"(
|
||||
library L {
|
||||
function f() private;
|
||||
}
|
||||
)";
|
||||
CHECK_ERROR(text, TypeError, "Internal library function must be implemented if declared.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user