mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #1592 from ethereum/internalConstructors
Disallow creation of contracts with internal constructors.
This commit is contained in:
commit
38bdc7a7dc
@ -75,7 +75,10 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
|||||||
checkContractAbstractConstructors(_contract);
|
checkContractAbstractConstructors(_contract);
|
||||||
|
|
||||||
FunctionDefinition const* function = _contract.constructor();
|
FunctionDefinition const* function = _contract.constructor();
|
||||||
if (function) {
|
if (function)
|
||||||
|
{
|
||||||
|
if (!function->isPublic())
|
||||||
|
_contract.annotation().hasPublicConstructor = false;
|
||||||
if (!function->returnParameters().empty())
|
if (!function->returnParameters().empty())
|
||||||
typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
|
typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
|
||||||
if (function->isDeclaredConst())
|
if (function->isDeclaredConst())
|
||||||
@ -1280,6 +1283,8 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
|||||||
fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
|
fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
|
||||||
if (!contract->annotation().isFullyImplemented)
|
if (!contract->annotation().isFullyImplemented)
|
||||||
typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
|
typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
|
||||||
|
if (!contract->annotation().hasPublicConstructor)
|
||||||
|
typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly.");
|
||||||
|
|
||||||
solAssert(!!m_scope, "");
|
solAssert(!!m_scope, "");
|
||||||
m_scope->annotation().contractDependencies.insert(contract);
|
m_scope->annotation().contractDependencies.insert(contract);
|
||||||
|
@ -80,6 +80,8 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnota
|
|||||||
{
|
{
|
||||||
/// Whether all functions are implemented.
|
/// Whether all functions are implemented.
|
||||||
bool isFullyImplemented = true;
|
bool isFullyImplemented = true;
|
||||||
|
/// Whether a public constructor (even the default one) is available.
|
||||||
|
bool hasPublicConstructor = true;
|
||||||
/// List of all (direct and indirect) base contracts in order from derived to
|
/// List of all (direct and indirect) base contracts in order from derived to
|
||||||
/// base, including the contract itself.
|
/// base, including the contract itself.
|
||||||
std::vector<ContractDefinition const*> linearizedBaseContracts;
|
std::vector<ContractDefinition const*> linearizedBaseContracts;
|
||||||
|
@ -624,7 +624,11 @@ void CompilerStack::compileContract(
|
|||||||
map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
|
map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (_compiledContracts.count(&_contract) || !_contract.annotation().isFullyImplemented)
|
if (
|
||||||
|
_compiledContracts.count(&_contract) ||
|
||||||
|
!_contract.annotation().isFullyImplemented ||
|
||||||
|
!_contract.annotation().hasPublicConstructor
|
||||||
|
)
|
||||||
return;
|
return;
|
||||||
for (auto const* dependency: _contract.annotation().contractDependencies)
|
for (auto const* dependency: _contract.annotation().contractDependencies)
|
||||||
compileContract(*dependency, _compiledContracts);
|
compileContract(*dependency, _compiledContracts);
|
||||||
|
@ -2505,6 +2505,16 @@ BOOST_AUTO_TEST_CASE(constructor_argument_overriding)
|
|||||||
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(3));
|
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(internal_constructor)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function C() internal {}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "C").empty());
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_modifier)
|
BOOST_AUTO_TEST_CASE(function_modifier)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
@ -4899,6 +4899,32 @@ BOOST_AUTO_TEST_CASE(assignment_to_constant)
|
|||||||
CHECK_ERROR(text, TypeError, "Cannot assign to a constant variable.");
|
CHECK_ERROR(text, TypeError, "Cannot assign to a constant variable.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inconstructible_internal_constructor)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function C() internal {}
|
||||||
|
}
|
||||||
|
contract D {
|
||||||
|
function f() { var x = new C(); }
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
CHECK_ERROR(text, TypeError, "Contract with internal constructor cannot be created directly.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(constructible_internal_constructor)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function C() internal {}
|
||||||
|
}
|
||||||
|
contract D is C {
|
||||||
|
function D() { }
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
success(text);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user