Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2020-11-24 16:22:03 +01:00
322 changed files with 1066 additions and 403 deletions
+16 -9
View File
@@ -394,6 +394,10 @@ bool OverrideProxy::OverrideComparator::operator<(OverrideComparator const& _oth
if (functionKind != _other.functionKind)
return *functionKind < *_other.functionKind;
// Parameters do not matter for non-regular functions.
if (functionKind != Token::Function)
return false;
if (!parameterTypes || !_other.parameterTypes)
return false;
@@ -574,16 +578,19 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
FunctionType const* functionType = _overriding.functionType();
FunctionType const* superType = _super.functionType();
solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!");
if (_overriding.functionKind() != Token::Fallback)
{
solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!");
if (!functionType->hasEqualReturnTypes(*superType))
overrideError(
_overriding,
_super,
4822_error,
"Overriding " + _overriding.astNodeName() + " return types differ.",
"Overridden " + _overriding.astNodeName() + " is here:"
);
if (!functionType->hasEqualReturnTypes(*superType))
overrideError(
_overriding,
_super,
4822_error,
"Overriding " + _overriding.astNodeName() + " return types differ.",
"Overridden " + _overriding.astNodeName() + " is here:"
);
}
// Stricter mutability is always okay except when super is Payable
if (
+13 -7
View File
@@ -1846,15 +1846,21 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function)
);
if (_function.visibility() != Visibility::External)
m_errorReporter.typeError(1159_error, _function.location(), "Fallback function must be defined as \"external\".");
if (!_function.returnParameters().empty())
if (!_function.returnParameters().empty() || !_function.parameters().empty())
{
if (_function.returnParameters().size() > 1 || *type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory())
m_errorReporter.typeError(5570_error, _function.returnParameterList()->location(), "Fallback function can only have a single \"bytes memory\" return value.");
else
m_errorReporter.typeError(6151_error, _function.returnParameterList()->location(), "Return values for fallback functions are not yet implemented.");
if (
_function.returnParameters().size() != 1 ||
*type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory() ||
_function.parameters().size() != 1 ||
*type(*_function.parameters().front()) != *TypeProvider::bytesCalldata()
)
m_errorReporter.typeError(
5570_error,
_function.returnParameterList()->location(),
"Fallback function either has to have the signature \"fallback()\" or \"fallback(bytes calldata) returns (bytes memory)\"."
);
}
if (!_function.parameters().empty())
m_errorReporter.typeError(3978_error, _function.parameterList().location(), "Fallback function cannot take parameters.");
}
void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function)
+5 -2
View File
@@ -170,6 +170,11 @@ public:
/// signature: (dataOffset, length, dataEnd) -> decodedArray
std::string abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory);
/// Internal decoding function that is also used by some copying routines.
/// @returns the name of a function that decodes structs.
/// signature: (dataStart, dataEnd) -> decodedStruct
std::string abiDecodingFunctionStruct(StructType const& _type, bool _fromMemory);
private:
/// Part of @a abiEncodingFunction for array target type and given calldata array.
/// Uses calldatacopy and does not perform cleanup or validation and can therefore only
@@ -245,8 +250,6 @@ private:
std::string abiDecodingFunctionCalldataStruct(StructType const& _type);
/// Part of @a abiDecodingFunction for array types.
std::string abiDecodingFunctionFunctionType(FunctionType const& _type, bool _fromMemory, bool _forUseOnStack);
/// Part of @a abiDecodingFunction for struct types.
std::string abiDecodingFunctionStruct(StructType const& _type, bool _fromMemory);
/// @returns the name of a function that retrieves an element from calldata.
std::string calldataAccessFunction(Type const& _type);
+34 -10
View File
@@ -478,10 +478,21 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
appendCallValueCheck();
solAssert(fallback->isFallback(), "");
solAssert(FunctionType(*fallback).parameterTypes().empty(), "");
solAssert(FunctionType(*fallback).returnParameterTypes().empty(), "");
m_context.setStackOffset(0);
if (!FunctionType(*fallback).parameterTypes().empty())
m_context << u256(0) << Instruction::CALLDATASIZE;
fallback->accept(*this);
m_context << Instruction::STOP;
if (FunctionType(*fallback).returnParameterTypes().empty())
m_context << Instruction::STOP;
else
{
m_context << Instruction::DUP1 << Instruction::MLOAD << Instruction::SWAP1;
m_context << u256(0x20) << Instruction::ADD;
m_context << Instruction::RETURN;
}
}
else
m_context.appendRevert("Unknown signature and no fallback defined");
@@ -490,6 +501,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
for (auto const& it: interfaceFunctions)
{
m_context.setStackOffset(1);
FunctionTypePointer const& functionType = it.second;
solAssert(functionType->hasDeclaration(), "");
CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration());
@@ -599,7 +611,9 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
// reserve additional slots: [retarg0] ... [retargm]
unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
if (!_function.isConstructor())
if (_function.isFallback())
m_context.adjustStackOffset(static_cast<int>(parametersSize));
else if (!_function.isConstructor())
// adding 1 for return address.
m_context.adjustStackOffset(static_cast<int>(parametersSize) + 1);
for (ASTPointer<VariableDeclaration> const& variable: _function.parameters())
@@ -609,7 +623,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
}
for (ASTPointer<VariableDeclaration> const& variable: _function.returnParameters())
appendStackVariableInitialisation(*variable);
appendStackVariableInitialisation(*variable, /* _provideDefaultValue = */ true);
if (_function.isConstructor())
if (auto c = dynamic_cast<ContractDefinition const&>(*_function.scope()).nextConstructor(
@@ -639,7 +653,8 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
vector<int> stackLayout;
stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
if (!_function.isConstructor() && !_function.isFallback())
stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
for (size_t i = 0; i < c_returnValuesSize; ++i)
stackLayout.push_back(static_cast<int>(i));
@@ -650,7 +665,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
errinfo_sourceLocation(_function.location()) <<
errinfo_comment("Stack too deep, try removing local variables.")
);
while (stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
while (!stackLayout.empty() && stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
if (stackLayout.back() < 0)
{
m_context << Instruction::POP;
@@ -1226,7 +1241,7 @@ bool ContractCompiler::visit(VariableDeclarationStatement const& _variableDeclar
// and freed in the end of their scope.
for (auto decl: _variableDeclarationStatement.declarations())
if (decl)
appendStackVariableInitialisation(*decl);
appendStackVariableInitialisation(*decl, !_variableDeclarationStatement.initialValue());
StackHeightChecker checker(m_context);
if (Expression const* expression = _variableDeclarationStatement.initialValue())
@@ -1391,11 +1406,20 @@ void ContractCompiler::appendModifierOrFunctionCode()
m_context.setModifierDepth(m_modifierDepth);
}
void ContractCompiler::appendStackVariableInitialisation(VariableDeclaration const& _variable)
void ContractCompiler::appendStackVariableInitialisation(
VariableDeclaration const& _variable,
bool _provideDefaultValue
)
{
CompilerContext::LocationSetter location(m_context, _variable);
m_context.addVariable(_variable);
CompilerUtils(m_context).pushZeroValue(*_variable.annotation().type);
if (!_provideDefaultValue && _variable.type()->dataStoredIn(DataLocation::Memory))
{
solAssert(_variable.type()->sizeOnStack() == 1, "");
m_context << u256(0);
}
else
CompilerUtils(m_context).pushZeroValue(*_variable.annotation().type);
}
void ContractCompiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
+4 -1
View File
@@ -130,7 +130,10 @@ private:
/// body itself if the last modifier was reached.
void appendModifierOrFunctionCode();
void appendStackVariableInitialisation(VariableDeclaration const& _variable);
/// Creates a stack slot for the given variable and assigns a default value.
/// If the default value is complex (needs memory allocation) and @a _provideDefaultValue
/// is false, this might be skipped.
void appendStackVariableInitialisation(VariableDeclaration const& _variable, bool _provideDefaultValue);
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
/// Frees the variables of a certain scope (to be used when leaving).
+8 -6
View File
@@ -3090,14 +3090,16 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
solUnimplementedAssert(fromStructType.location() != DataLocation::Memory, "");
if (fromStructType.location() == DataLocation::CallData)
{
solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), "");
body = Whiskers(R"(
converted := <abiDecode>(value, calldatasize())
)")("abiDecode", ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).tupleDecoder(
{&toStructType}
)).render();
}
)")
(
"abiDecode",
ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).abiDecodingFunctionStruct(
toStructType,
false
)
).render();
else
{
solAssert(fromStructType.location() == DataLocation::Storage, "");
+10 -2
View File
@@ -652,8 +652,16 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
{
string fallbackCode;
if (!fallback->isPayable())
fallbackCode += callValueCheck();
fallbackCode += m_context.enqueueFunctionForCodeGeneration(*fallback) + "() stop()";
fallbackCode += callValueCheck() + "\n";
if (fallback->parameters().empty())
fallbackCode += m_context.enqueueFunctionForCodeGeneration(*fallback) + "() stop()";
else
{
solAssert(fallback->parameters().size() == 1 && fallback->returnParameters().size() == 1, "");
fallbackCode += "let retval := " + m_context.enqueueFunctionForCodeGeneration(*fallback) + "(0, calldatasize())\n";
fallbackCode += "return(add(retval, 0x20), mload(retval))\n";
}
t("fallback", fallbackCode);
}
+1 -1
View File
@@ -1119,7 +1119,7 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess)
}
else
// NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not
// at all useable in the SMT checker currently
// at all usable in the SMT checker currently
m_errorReporter.warning(
7507_error,
_memberAccess.location(),