aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/analysis/TypeChecker.cpp7
-rw-r--r--libsolidity/ast/ASTAnnotations.h2
-rw-r--r--libsolidity/interface/CompilerStack.cpp6
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp10
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp26
5 files changed, 49 insertions, 2 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 67c8ac17..adb3d54f 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -75,7 +75,10 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
checkContractAbstractConstructors(_contract);
FunctionDefinition const* function = _contract.constructor();
- if (function) {
+ if (function)
+ {
+ if (!function->isPublic())
+ _contract.annotation().hasPublicConstructor = false;
if (!function->returnParameters().empty())
typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
if (function->isDeclaredConst())
@@ -1280,6 +1283,8 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
if (!contract->annotation().isFullyImplemented)
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, "");
m_scope->annotation().contractDependencies.insert(contract);
diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h
index 9c4c3ae8..61e97a55 100644
--- a/libsolidity/ast/ASTAnnotations.h
+++ b/libsolidity/ast/ASTAnnotations.h
@@ -80,6 +80,8 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnota
{
/// Whether all functions are implemented.
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
/// base, including the contract itself.
std::vector<ContractDefinition const*> linearizedBaseContracts;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 85ec0fb1..b26bd501 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -624,7 +624,11 @@ void CompilerStack::compileContract(
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;
for (auto const* dependency: _contract.annotation().contractDependencies)
compileContract(*dependency, _compiledContracts);
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 19161831..63a5828e 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2505,6 +2505,16 @@ BOOST_AUTO_TEST_CASE(constructor_argument_overriding)
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)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 9f6ea2b3..edb57b0d 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -4899,6 +4899,32 @@ BOOST_AUTO_TEST_CASE(assignment_to_constant)
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()
}