mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9106 from ethereum/develop
Merge develop into breaking.
This commit is contained in:
@@ -693,14 +693,6 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (!var || !type(*var)->isValueType() || (
|
||||
dynamic_cast<Literal const*>(var->value().get()) == nullptr &&
|
||||
type(*var->value())->category() != Type::Category::RationalNumber
|
||||
))
|
||||
{
|
||||
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
|
||||
@@ -711,8 +703,27 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
2249_error,
|
||||
_identifier.location,
|
||||
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
|
||||
);
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (!var || !type(*var)->isValueType() || (
|
||||
!dynamic_cast<Literal const*>(var->value().get()) &&
|
||||
type(*var->value())->category() != Type::Category::RationalNumber
|
||||
))
|
||||
{
|
||||
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
|
||||
return size_t(-1);
|
||||
}
|
||||
}
|
||||
|
||||
solAssert(!dynamic_cast<FixedPointType const*>(var->type()), "FixedPointType not implemented.");
|
||||
|
||||
if (requiresStorage)
|
||||
{
|
||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||
@@ -2983,7 +2994,11 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
if (!annotation.referencedDeclaration)
|
||||
{
|
||||
annotation.overloadedDeclarations = cleanOverloadedDeclarations(_identifier, annotation.candidateDeclarations);
|
||||
if (!annotation.arguments)
|
||||
if (annotation.overloadedDeclarations.empty())
|
||||
m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found.");
|
||||
else if (annotation.overloadedDeclarations.size() == 1)
|
||||
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
|
||||
else if (!annotation.arguments)
|
||||
{
|
||||
// The identifier should be a public state variable shadowing other functions
|
||||
vector<Declaration const*> candidates;
|
||||
@@ -3000,10 +3015,6 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
else
|
||||
m_errorReporter.fatalTypeError(7589_error, _identifier.location(), "No unique declaration found after variable lookup.");
|
||||
}
|
||||
else if (annotation.overloadedDeclarations.empty())
|
||||
m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found.");
|
||||
else if (annotation.overloadedDeclarations.size() == 1)
|
||||
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
|
||||
else
|
||||
{
|
||||
vector<Declaration const*> candidates;
|
||||
|
||||
@@ -172,8 +172,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
|
||||
++slotOffset;
|
||||
byteOffset = 0;
|
||||
}
|
||||
if (slotOffset >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Object too large for storage."));
|
||||
solAssert(slotOffset < bigint(1) << 256 ,"Object too large for storage.");
|
||||
offsets[i] = make_pair(u256(slotOffset), byteOffset);
|
||||
solAssert(type->storageSize() >= 1, "Invalid storage size.");
|
||||
if (type->storageSize() == 1 && byteOffset + type->storageBytes() <= 32)
|
||||
@@ -186,8 +185,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
|
||||
}
|
||||
if (byteOffset > 0)
|
||||
++slotOffset;
|
||||
if (slotOffset >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Object too large for storage."));
|
||||
solAssert(slotOffset < bigint(1) << 256, "Object too large for storage.");
|
||||
m_storageSize = u256(slotOffset);
|
||||
swap(m_offsets, offsets);
|
||||
}
|
||||
@@ -1776,8 +1774,7 @@ u256 ArrayType::storageSize() const
|
||||
}
|
||||
else
|
||||
size = bigint(length()) * baseType()->storageSize();
|
||||
if (size >= bigint(1) << 256)
|
||||
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Array too large for storage."));
|
||||
solAssert(size < bigint(1) << 256, "Array too large for storage.");
|
||||
return max<u256>(1, u256(size));
|
||||
}
|
||||
|
||||
|
||||
@@ -422,7 +422,12 @@ void CompilerContext::appendInlineAssembly(
|
||||
ErrorReporter errorReporter(errors);
|
||||
auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly, "--CODEGEN--"));
|
||||
yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
|
||||
shared_ptr<yul::Block> parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false);
|
||||
optional<langutil::SourceLocation> locationOverride;
|
||||
if (!_system)
|
||||
locationOverride = m_asm->currentSourceLocation();
|
||||
shared_ptr<yul::Block> parserResult =
|
||||
yul::Parser(errorReporter, dialect, std::move(locationOverride))
|
||||
.parse(scanner, false);
|
||||
#ifdef SOL_OUTPUT_ASM
|
||||
cout << yul::AsmPrinter(&dialect)(*parserResult) << endl;
|
||||
#endif
|
||||
|
||||
@@ -701,7 +701,7 @@ vector<smtutil::SortPointer> CHC::stateSorts(ContractDefinition const& _contract
|
||||
smtutil::SortPointer CHC::constructorSort()
|
||||
{
|
||||
return make_shared<smtutil::FunctionSort>(
|
||||
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts,
|
||||
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts,
|
||||
smtutil::SortProvider::boolSort
|
||||
);
|
||||
}
|
||||
@@ -747,7 +747,7 @@ smtutil::SortPointer CHC::sort(FunctionDefinition const& _function)
|
||||
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
||||
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
||||
return make_shared<smtutil::FunctionSort>(
|
||||
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
|
||||
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
|
||||
smtutil::SortProvider::boolSort
|
||||
);
|
||||
}
|
||||
@@ -776,7 +776,7 @@ smtutil::SortPointer CHC::summarySort(FunctionDefinition const& _function, Contr
|
||||
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
||||
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
||||
return make_shared<smtutil::FunctionSort>(
|
||||
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + sorts + inputSorts + sorts + outputSorts,
|
||||
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + sorts + inputSorts + sorts + outputSorts,
|
||||
smtutil::SortProvider::boolSort
|
||||
);
|
||||
}
|
||||
|
||||
@@ -274,6 +274,20 @@ bool SMTEncoder::visit(InlineAssembly const& _inlineAsm)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SMTEncoder::visit(TryCatchClause const& _clause)
|
||||
{
|
||||
if (auto params = _clause.parameters())
|
||||
for (auto const& var: params->parameters())
|
||||
createVariable(*var);
|
||||
|
||||
m_errorReporter.warning(
|
||||
7645_error,
|
||||
_clause.location(),
|
||||
"Assertion checker does not support try/catch clauses."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SMTEncoder::visit(IfStatement const& _node)
|
||||
{
|
||||
_node.condition().accept(*this);
|
||||
@@ -361,7 +375,12 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
|
||||
else if (!smt::isSupportedType(_assignment.annotation().type->category()))
|
||||
{
|
||||
// Give it a new index anyway to keep the SSA scheme sound.
|
||||
if (auto varDecl = identifierToVariable(_assignment.leftHandSide()))
|
||||
|
||||
Expression const* base = &_assignment.leftHandSide();
|
||||
if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(base))
|
||||
base = leftmostBase(*indexAccess);
|
||||
|
||||
if (auto varDecl = identifierToVariable(*base))
|
||||
m_context.newValue(*varDecl);
|
||||
}
|
||||
else
|
||||
@@ -463,9 +482,6 @@ void SMTEncoder::endVisit(UnaryOperation const& _op)
|
||||
|
||||
createExpr(_op);
|
||||
|
||||
if (_op.annotation().type->category() == Type::Category::FixedPoint)
|
||||
return;
|
||||
|
||||
switch (_op.getOperator())
|
||||
{
|
||||
case Token::Not: // !
|
||||
@@ -477,8 +493,8 @@ void SMTEncoder::endVisit(UnaryOperation const& _op)
|
||||
case Token::Inc: // ++ (pre- or postfix)
|
||||
case Token::Dec: // -- (pre- or postfix)
|
||||
{
|
||||
|
||||
solAssert(smt::isInteger(_op.annotation().type->category()), "");
|
||||
auto cat = _op.annotation().type->category();
|
||||
solAssert(smt::isInteger(cat) || smt::isFixedPoint(cat), "");
|
||||
solAssert(_op.subExpression().annotation().willBeWrittenTo, "");
|
||||
if (auto identifier = dynamic_cast<Identifier const*>(&_op.subExpression()))
|
||||
{
|
||||
@@ -574,6 +590,8 @@ void SMTEncoder::endVisit(BinaryOperation const& _op)
|
||||
arithmeticOperation(_op);
|
||||
else if (TokenTraits::isCompareOp(_op.getOperator()))
|
||||
compareOperation(_op);
|
||||
else if (TokenTraits::isBitOp(_op.getOperator()))
|
||||
bitwiseOperation(_op);
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
3876_error,
|
||||
@@ -1146,6 +1164,12 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression
|
||||
}
|
||||
else if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(&_expr))
|
||||
arrayIndexAssignment(*indexAccess, _array);
|
||||
else if (dynamic_cast<MemberAccess const*>(&_expr))
|
||||
m_errorReporter.warning(
|
||||
9599_error,
|
||||
_expr.location(),
|
||||
"Assertion checker does not yet implement this expression."
|
||||
);
|
||||
else
|
||||
solAssert(false, "");
|
||||
}
|
||||
@@ -1346,6 +1370,43 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op)
|
||||
);
|
||||
}
|
||||
|
||||
void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
|
||||
{
|
||||
solAssert(TokenTraits::isBitOp(_op.getOperator()), "");
|
||||
auto commonType = _op.annotation().commonType;
|
||||
solAssert(commonType, "");
|
||||
|
||||
unsigned bvSize = 256;
|
||||
bool isSigned = false;
|
||||
if (auto const* intType = dynamic_cast<IntegerType const*>(commonType))
|
||||
{
|
||||
bvSize = intType->numBits();
|
||||
isSigned = intType->isSigned();
|
||||
}
|
||||
else if (auto const* fixedType = dynamic_cast<FixedPointType const*>(commonType))
|
||||
{
|
||||
bvSize = fixedType->numBits();
|
||||
isSigned = fixedType->isSigned();
|
||||
}
|
||||
|
||||
auto bvLeft = smtutil::Expression::int2bv(expr(_op.leftExpression()), bvSize);
|
||||
auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression()), bvSize);
|
||||
|
||||
optional<smtutil::Expression> result;
|
||||
if (_op.getOperator() == Token::BitAnd)
|
||||
result = bvLeft & bvRight;
|
||||
// TODO implement the other operators
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
1093_error,
|
||||
_op.location(),
|
||||
"Assertion checker does not yet implement this bitwise operator."
|
||||
);
|
||||
|
||||
if (result)
|
||||
defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned));
|
||||
}
|
||||
|
||||
smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type)
|
||||
{
|
||||
// Signed division in SMTLIB2 rounds differently for negative division.
|
||||
@@ -1755,7 +1816,6 @@ Expression const* SMTEncoder::leftmostBase(IndexAccess const& _indexAccess)
|
||||
|
||||
set<VariableDeclaration const*> SMTEncoder::touchedVariables(ASTNode const& _node)
|
||||
{
|
||||
solAssert(!m_callStack.empty(), "");
|
||||
vector<CallableDeclaration const*> callStack;
|
||||
for (auto const& call: m_callStack)
|
||||
callStack.push_back(call.first);
|
||||
|
||||
@@ -91,6 +91,7 @@ protected:
|
||||
bool visit(InlineAssembly const& _node) override;
|
||||
void endVisit(Break const&) override {}
|
||||
void endVisit(Continue const&) override {}
|
||||
bool visit(TryCatchClause const& _node) override;
|
||||
|
||||
/// Do not visit subtree if node is a RationalNumber.
|
||||
/// Symbolic _expr is the rational literal.
|
||||
@@ -108,6 +109,7 @@ protected:
|
||||
);
|
||||
void compareOperation(BinaryOperation const& _op);
|
||||
void booleanOperation(BinaryOperation const& _op);
|
||||
void bitwiseOperation(BinaryOperation const& _op);
|
||||
|
||||
void initContract(ContractDefinition const& _contract);
|
||||
void initFunction(FunctionDefinition const& _function);
|
||||
|
||||
@@ -63,7 +63,7 @@ private:
|
||||
|
||||
/// Symbolic balances.
|
||||
SymbolicArrayVariable m_balances{
|
||||
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::intSort, smtutil::SortProvider::intSort),
|
||||
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort),
|
||||
"balances",
|
||||
m_context
|
||||
};
|
||||
|
||||
@@ -34,7 +34,11 @@ SortPointer smtSort(frontend::Type const& _type)
|
||||
switch (smtKind(_type.category()))
|
||||
{
|
||||
case Kind::Int:
|
||||
return SortProvider::intSort;
|
||||
if (auto const* intType = dynamic_cast<IntegerType const*>(&_type))
|
||||
return SortProvider::intSort(intType->isSigned());
|
||||
if (auto const* fixedType = dynamic_cast<FixedPointType const*>(&_type))
|
||||
return SortProvider::intSort(fixedType->isSigned());
|
||||
return SortProvider::uintSort;
|
||||
case Kind::Bool:
|
||||
return SortProvider::boolSort;
|
||||
case Kind::Function:
|
||||
@@ -50,7 +54,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
||||
returnSort = SortProvider::boolSort;
|
||||
else if (returnTypes.size() > 1)
|
||||
// Abstract sort.
|
||||
returnSort = SortProvider::intSort;
|
||||
returnSort = SortProvider::uintSort;
|
||||
else
|
||||
returnSort = smtSort(*returnTypes.front());
|
||||
return make_shared<FunctionSort>(parameterSorts, returnSort);
|
||||
@@ -68,7 +72,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
||||
{
|
||||
auto stringLitType = dynamic_cast<frontend::StringLiteralType const*>(&_type);
|
||||
solAssert(stringLitType, "");
|
||||
array = make_shared<ArraySort>(SortProvider::intSort, SortProvider::intSort);
|
||||
array = make_shared<ArraySort>(SortProvider::uintSort, SortProvider::uintSort);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -81,7 +85,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
||||
solAssert(false, "");
|
||||
|
||||
solAssert(arrayType, "");
|
||||
array = make_shared<ArraySort>(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType()));
|
||||
array = make_shared<ArraySort>(SortProvider::uintSort, smtSortAbstractFunction(*arrayType->baseType()));
|
||||
}
|
||||
|
||||
string tupleName;
|
||||
@@ -98,7 +102,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
||||
return make_shared<TupleSort>(
|
||||
tupleName,
|
||||
vector<string>{tupleName + "_accessor_array", tupleName + "_accessor_length"},
|
||||
vector<SortPointer>{array, SortProvider::intSort}
|
||||
vector<SortPointer>{array, SortProvider::uintSort}
|
||||
);
|
||||
}
|
||||
case Kind::Tuple:
|
||||
@@ -118,7 +122,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
||||
}
|
||||
default:
|
||||
// Abstract case.
|
||||
return SortProvider::intSort;
|
||||
return SortProvider::uintSort;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +137,7 @@ vector<SortPointer> smtSort(vector<frontend::TypePointer> const& _types)
|
||||
SortPointer smtSortAbstractFunction(frontend::Type const& _type)
|
||||
{
|
||||
if (isFunction(_type.category()))
|
||||
return SortProvider::intSort;
|
||||
return SortProvider::uintSort;
|
||||
return smtSort(_type);
|
||||
}
|
||||
|
||||
@@ -144,7 +148,7 @@ vector<SortPointer> smtSortAbstractFunction(vector<frontend::TypePointer> const&
|
||||
if (type)
|
||||
sorts.push_back(smtSortAbstractFunction(*type));
|
||||
else
|
||||
sorts.push_back(SortProvider::intSort);
|
||||
sorts.push_back(SortProvider::uintSort);
|
||||
return sorts;
|
||||
}
|
||||
|
||||
@@ -220,6 +224,8 @@ pair<bool, shared_ptr<SymbolicVariable>> newSymbolicVariable(
|
||||
}
|
||||
else if (isInteger(_type.category()))
|
||||
var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context);
|
||||
else if (isFixedPoint(_type.category()))
|
||||
var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context);
|
||||
else if (isFixedBytes(_type.category()))
|
||||
{
|
||||
auto fixedBytesType = dynamic_cast<frontend::FixedBytesType const*>(type);
|
||||
@@ -268,6 +274,11 @@ bool isInteger(frontend::Type::Category _category)
|
||||
return _category == frontend::Type::Category::Integer;
|
||||
}
|
||||
|
||||
bool isFixedPoint(frontend::Type::Category _category)
|
||||
{
|
||||
return _category == frontend::Type::Category::FixedPoint;
|
||||
}
|
||||
|
||||
bool isRational(frontend::Type::Category _category)
|
||||
{
|
||||
return _category == frontend::Type::Category::RationalNumber;
|
||||
@@ -296,6 +307,7 @@ bool isEnum(frontend::Type::Category _category)
|
||||
bool isNumber(frontend::Type::Category _category)
|
||||
{
|
||||
return isInteger(_category) ||
|
||||
isFixedPoint(_category) ||
|
||||
isRational(_category) ||
|
||||
isFixedBytes(_category) ||
|
||||
isAddress(_category) ||
|
||||
|
||||
@@ -43,6 +43,7 @@ bool isSupportedTypeDeclaration(frontend::Type::Category _category);
|
||||
bool isSupportedTypeDeclaration(frontend::Type const& _type);
|
||||
|
||||
bool isInteger(frontend::Type::Category _category);
|
||||
bool isFixedPoint(frontend::Type::Category _category);
|
||||
bool isRational(frontend::Type::Category _category);
|
||||
bool isFixedBytes(frontend::Type::Category _category);
|
||||
bool isAddress(frontend::Type::Category _category);
|
||||
|
||||
@@ -286,7 +286,7 @@ SymbolicArrayVariable::SymbolicArrayVariable(
|
||||
std::make_shared<TupleSort>(
|
||||
"array_length_pair",
|
||||
std::vector<std::string>{"array", "length"},
|
||||
std::vector<SortPointer>{m_sort, SortProvider::intSort}
|
||||
std::vector<SortPointer>{m_sort, SortProvider::uintSort}
|
||||
),
|
||||
m_uniqueName + "_array_length_pair",
|
||||
m_context
|
||||
|
||||
@@ -33,7 +33,8 @@ set<VariableDeclaration const*> VariableUsage::touchedVariables(ASTNode const& _
|
||||
m_touchedVariables.clear();
|
||||
m_callStack.clear();
|
||||
m_callStack += _outerCallstack;
|
||||
m_lastCall = m_callStack.back();
|
||||
if (!m_callStack.empty())
|
||||
m_lastCall = m_callStack.back();
|
||||
_node.accept(*this);
|
||||
return m_touchedVariables;
|
||||
}
|
||||
@@ -103,8 +104,7 @@ void VariableUsage::checkIdentifier(Identifier const& _identifier)
|
||||
solAssert(declaration, "");
|
||||
if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
{
|
||||
solAssert(m_lastCall, "");
|
||||
if (!varDecl->isLocalVariable() || varDecl->functionOrModifierDefinition() == m_lastCall)
|
||||
if (!varDecl->isLocalVariable() || (m_lastCall && varDecl->functionOrModifierDefinition() == m_lastCall))
|
||||
m_touchedVariables.insert(varDecl);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user