mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
@@ -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 (
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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, "");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user