aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/analysis/DeclarationContainer.cpp10
-rw-r--r--libsolidity/analysis/PostTypeChecker.cpp5
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp2
-rw-r--r--libsolidity/analysis/TypeChecker.cpp50
-rw-r--r--libsolidity/ast/Types.cpp13
-rw-r--r--libsolidity/ast/Types.h4
-rw-r--r--libsolidity/formal/SMTChecker.cpp20
-rw-r--r--libsolidity/formal/SMTPortfolio.cpp1
8 files changed, 60 insertions, 45 deletions
diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp
index 9e2bf6d3..347daaf8 100644
--- a/libsolidity/analysis/DeclarationContainer.cpp
+++ b/libsolidity/analysis/DeclarationContainer.cpp
@@ -49,16 +49,10 @@ Declaration const* DeclarationContainer::conflictingDeclaration(
dynamic_cast<MagicVariableDeclaration const*>(&_declaration)
)
{
- // check that all other declarations with the same name are functions or a public state variable or events.
- // And then check that the signatures are different.
+ // check that all other declarations are of the same kind (in which
+ // case the type checker will ensure that the signatures are different)
for (Declaration const* declaration: declarations)
{
- if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(declaration))
- {
- if (variableDeclaration->isStateVariable() && !variableDeclaration->isConstant() && variableDeclaration->isPublic())
- continue;
- return declaration;
- }
if (
dynamic_cast<FunctionDefinition const*>(&_declaration) &&
!dynamic_cast<FunctionDefinition const*>(declaration)
diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp
index 19d0b708..240d7973 100644
--- a/libsolidity/analysis/PostTypeChecker.cpp
+++ b/libsolidity/analysis/PostTypeChecker.cpp
@@ -91,8 +91,11 @@ bool PostTypeChecker::visit(Identifier const& _identifier)
VariableDeclaration const* PostTypeChecker::findCycle(VariableDeclaration const& _startingFrom)
{
- auto visitor = [&](VariableDeclaration const& _variable, CycleDetector<VariableDeclaration>& _cycleDetector)
+ auto visitor = [&](VariableDeclaration const& _variable, CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth)
{
+ if (_depth >= 256)
+ m_errorReporter.fatalDeclarationError(_variable.location(), "Variable definition exhausting cyclic dependency validator.");
+
// Iterating through the dependencies needs to be deterministic and thus cannot
// depend on the memory layout.
// Because of that, we sort by AST node id.
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 5815e3d2..a9a998b0 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -144,7 +144,7 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
if (!declaration)
{
- declarationError(_typeName.location(), "Identifier not found or not unique.");
+ fatalDeclarationError(_typeName.location(), "Identifier not found or not unique.");
return;
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 8536e934..8f504ffe 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -22,6 +22,7 @@
#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>
@@ -278,8 +279,6 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
void TypeChecker::checkContractBaseConstructorArguments(ContractDefinition const& _contract)
{
- bool const v050 = _contract.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050);
-
vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
// Determine the arguments that are used for the base constructors.
@@ -287,27 +286,19 @@ void TypeChecker::checkContractBaseConstructorArguments(ContractDefinition const
{
if (FunctionDefinition const* constructor = contract->constructor())
for (auto const& modifier: constructor->modifiers())
- {
- auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(*modifier->name()));
- if (modifier->arguments())
- {
- if (baseContract && baseContract->constructor())
- annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
- }
- else
+ if (auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(*modifier->name())))
{
- if (v050)
- m_errorReporter.declarationError(
- modifier->location(),
- "Modifier-style base constructor call without arguments."
- );
+ if (modifier->arguments())
+ {
+ if (baseContract->constructor())
+ annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
+ }
else
- m_errorReporter.warning(
+ m_errorReporter.declarationError(
modifier->location(),
"Modifier-style base constructor call without arguments."
);
}
- }
for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
{
@@ -594,8 +585,11 @@ bool TypeChecker::visit(StructDefinition const& _struct)
m_errorReporter.typeError(member->location(), "Type cannot be used in struct.");
// Check recursion, fatal error if detected.
- auto visitor = [&](StructDefinition const& _struct, CycleDetector<StructDefinition>& _cycleDetector)
+ auto visitor = [&](StructDefinition const& _struct, CycleDetector<StructDefinition>& _cycleDetector, size_t _depth)
{
+ if (_depth >= 256)
+ m_errorReporter.fatalDeclarationError(_struct.location(), "Struct definition exhausting cyclic dependency validator.");
+
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
{
Type const* memberType = type(*member).get();
@@ -709,6 +703,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
// TypeChecker at the VariableDeclarationStatement level.
TypePointer varType = _variable.annotation().type;
solAssert(!!varType, "Failed to infer variable type.");
+
if (_variable.value())
expectType(*_variable.value(), *varType);
if (_variable.isConstant())
@@ -1079,10 +1074,25 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
{
// No initial value is only permitted for single variables with specified type.
if (_statement.declarations().size() != 1 || !_statement.declarations().front())
- m_errorReporter.fatalTypeError(_statement.location(), "Assignment necessary for type detection.");
+ {
+ if (boost::algorithm::all_of_equal(_statement.declarations(), nullptr))
+ {
+ // The syntax checker has already generated an error for this case (empty LHS tuple).
+ solAssert(m_errorReporter.hasErrors(), "");
+
+ // It is okay to return here, as there are no named components on the
+ // left-hand-side that could cause any damage later.
+ return false;
+ }
+ else
+ // Bailing out *fatal* here, as those (untyped) vars may be used later, and diagnostics wouldn't be helpful then.
+ m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed.");
+ }
+
VariableDeclaration const& varDecl = *_statement.declarations().front();
if (!varDecl.annotation().type)
- m_errorReporter.fatalTypeError(_statement.location(), "Assignment necessary for type detection.");
+ m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed.");
+
if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl).get()))
{
if (ref->dataStoredIn(DataLocation::Storage))
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 2c2d3b68..c85e0522 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -1403,15 +1403,15 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (*this == _convertTo)
return true;
- if (_convertTo.category() == Category::Integer)
- return dynamic_cast<IntegerType const&>(_convertTo).isAddress();
if (_convertTo.category() == Category::Contract)
{
auto const& bases = contractDefinition().annotation().linearizedBaseContracts;
if (m_super && bases.size() <= 1)
return false;
- return find(m_super ? ++bases.begin() : bases.begin(), bases.end(),
- &dynamic_cast<ContractType const&>(_convertTo).contractDefinition()) != bases.end();
+ return find(
+ m_super ? ++bases.begin() : bases.begin(), bases.end(),
+ &dynamic_cast<ContractType const&>(_convertTo).contractDefinition()
+ ) != bases.end();
}
return false;
}
@@ -1420,8 +1420,7 @@ bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return
isImplicitlyConvertibleTo(_convertTo) ||
- _convertTo.category() == Category::Integer ||
- _convertTo.category() == Category::Contract;
+ _convertTo == IntegerType(160, IntegerType::Modifier::Address);
}
bool ContractType::isPayable() const
@@ -2120,7 +2119,7 @@ bool StructType::recursive() const
{
if (!m_recursive.is_initialized())
{
- auto visitor = [&](StructDefinition const& _struct, CycleDetector<StructDefinition>& _cycleDetector)
+ auto visitor = [&](StructDefinition const& _struct, CycleDetector<StructDefinition>& _cycleDetector, size_t /*_depth*/)
{
for (ASTPointer<VariableDeclaration> const& variable: _struct.members())
{
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 1a676b42..474a6f33 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -692,9 +692,9 @@ public:
virtual Category category() const override { return Category::Contract; }
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
m_contract(_contract), m_super(_super) {}
- /// Contracts can be implicitly converted to super classes and to addresses.
+ /// Contracts can be implicitly converted only to base contracts.
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- /// Contracts can be converted to themselves and to integers.
+ /// Contracts can only be explicitly converted to address types and base contracts.
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual std::string richIdentifier() const override;
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index 109c8dbe..17b50a38 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -252,14 +252,14 @@ void SMTChecker::checkUnderOverflow(smt::Expression _value, IntegerType const& _
_value < SymbolicIntVariable::minValue(_type),
_location,
"Underflow (resulting value less than " + formatNumber(_type.minValue()) + ")",
- "value",
+ "<result>",
&_value
);
checkCondition(
_value > SymbolicIntVariable::maxValue(_type),
_location,
"Overflow (resulting value larger than " + formatNumber(_type.maxValue()) + ")",
- "value",
+ "<result>",
&_value
);
}
@@ -437,7 +437,7 @@ void SMTChecker::arithmeticOperation(BinaryOperation const& _op)
if (_op.getOperator() == Token::Div)
{
- checkCondition(right == 0, _op.location(), "Division by zero", "value", &right);
+ checkCondition(right == 0, _op.location(), "Division by zero", "<result>", &right);
m_interface->addAssertion(right != 0);
}
@@ -601,15 +601,23 @@ void SMTChecker::checkCondition(
message << _description << " happens here";
if (m_currentFunction)
{
- message << " for:\n";
+ std::ostringstream modelMessage;
+ modelMessage << " for:\n";
solAssert(values.size() == expressionNames.size(), "");
+ map<string, string> sortedModel;
for (size_t i = 0; i < values.size(); ++i)
if (expressionsToEvaluate.at(i).name != values.at(i))
- message << " " << expressionNames.at(i) << " = " << values.at(i) << "\n";
+ sortedModel[expressionNames.at(i)] = values.at(i);
+
+ for (auto const& eval: sortedModel)
+ modelMessage << " " << eval.first << " = " << eval.second << "\n";
+ m_errorReporter.warning(_location, message.str() + loopComment, SecondarySourceLocation().append(modelMessage.str(), SourceLocation()));
}
else
+ {
message << ".";
- m_errorReporter.warning(_location, message.str() + loopComment);
+ m_errorReporter.warning(_location, message.str() + loopComment);
+ }
break;
}
case smt::CheckResult::UNSATISFIABLE:
diff --git a/libsolidity/formal/SMTPortfolio.cpp b/libsolidity/formal/SMTPortfolio.cpp
index 64806097..8b9fe9ce 100644
--- a/libsolidity/formal/SMTPortfolio.cpp
+++ b/libsolidity/formal/SMTPortfolio.cpp
@@ -29,6 +29,7 @@
using namespace std;
using namespace dev;
+using namespace dev::solidity;
using namespace dev::solidity::smt;
SMTPortfolio::SMTPortfolio(ReadCallback::Callback const& _readCallback)