mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12565 from ethereum/ice-convert-string-bytes-11677
Fix ICE when converting from calldata string to bytes
This commit is contained in:
commit
40d3223bba
@ -12,12 +12,13 @@ Compiler Features:
|
|||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
* Antlr Grammar: Allow builtin names in ``yulPath`` to support ``.address`` in function pointers.
|
* Antlr Grammar: Allow builtin names in ``yulPath`` to support ``.address`` in function pointers.
|
||||||
|
* Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots.
|
||||||
|
* Code Generator: Fix ICE when doing an explicit conversion from ``string calldata`` to ``bytes``.
|
||||||
* Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis.
|
* Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis.
|
||||||
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables.
|
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables.
|
||||||
* IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions.
|
* IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions.
|
||||||
* Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different.
|
* Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different.
|
||||||
* TypeChecker: Fix ICE when a constant variable declaration forward references a struct.
|
* TypeChecker: Fix ICE when a constant variable declaration forward references a struct.
|
||||||
* Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots.
|
|
||||||
|
|
||||||
|
|
||||||
Solc-Js:
|
Solc-Js:
|
||||||
|
@ -54,7 +54,7 @@ static_assert(CompilerUtils::generalPurposeMemoryStart >= CompilerUtils::zeroPoi
|
|||||||
void CompilerUtils::initialiseFreeMemoryPointer()
|
void CompilerUtils::initialiseFreeMemoryPointer()
|
||||||
{
|
{
|
||||||
size_t reservedMemory = m_context.reservedMemory();
|
size_t reservedMemory = m_context.reservedMemory();
|
||||||
solAssert(bigint(generalPurposeMemoryStart) + bigint(reservedMemory) < bigint(1) << 63, "");
|
solAssert(bigint(generalPurposeMemoryStart) + bigint(reservedMemory) < bigint(1) << 63);
|
||||||
m_context << (u256(generalPurposeMemoryStart) + reservedMemory);
|
m_context << (u256(generalPurposeMemoryStart) + reservedMemory);
|
||||||
storeFreeMemoryPointer();
|
storeFreeMemoryPointer();
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer()
|
|||||||
|
|
||||||
void CompilerUtils::revertWithStringData(Type const& _argumentType)
|
void CompilerUtils::revertWithStringData(Type const& _argumentType)
|
||||||
{
|
{
|
||||||
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")), "");
|
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")));
|
||||||
fetchFreeMemoryPointer();
|
fetchFreeMemoryPointer();
|
||||||
m_context << util::selectorFromSignature("Error(string)");
|
m_context << util::selectorFromSignature("Error(string)");
|
||||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||||
@ -173,9 +173,9 @@ void CompilerUtils::loadFromMemoryDynamic(
|
|||||||
|
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||||
{
|
{
|
||||||
solAssert(!arrayType->isDynamicallySized(), "");
|
solAssert(!arrayType->isDynamicallySized());
|
||||||
solAssert(!_fromCalldata, "");
|
solAssert(!_fromCalldata);
|
||||||
solAssert(_padToWordBoundaries, "");
|
solAssert(_padToWordBoundaries);
|
||||||
if (_keepUpdatedMemoryOffset)
|
if (_keepUpdatedMemoryOffset)
|
||||||
m_context << arrayType->memoryDataSize() << Instruction::ADD;
|
m_context << arrayType->memoryDataSize() << Instruction::ADD;
|
||||||
}
|
}
|
||||||
@ -251,7 +251,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
|||||||
// Use the new Yul-based decoding function
|
// Use the new Yul-based decoding function
|
||||||
auto stackHeightBefore = m_context.stackHeight();
|
auto stackHeightBefore = m_context.stackHeight();
|
||||||
abiDecodeV2(_typeParameters, _fromMemory);
|
abiDecodeV2(_typeParameters, _fromMemory);
|
||||||
solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2, "");
|
solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
|||||||
);
|
);
|
||||||
// @todo If base type is an array or struct, it is still calldata-style encoded, so
|
// @todo If base type is an array or struct, it is still calldata-style encoded, so
|
||||||
// we would have to convert it like below.
|
// we would have to convert it like below.
|
||||||
solAssert(arrayType.location() == DataLocation::Memory, "");
|
solAssert(arrayType.location() == DataLocation::Memory);
|
||||||
if (arrayType.isDynamicallySized())
|
if (arrayType.isDynamicallySized())
|
||||||
{
|
{
|
||||||
// compute data pointer
|
// compute data pointer
|
||||||
@ -430,7 +430,7 @@ void CompilerUtils::encodeToMemory(
|
|||||||
// stack: <v1> <v2> ... <vn> <mem>
|
// stack: <v1> <v2> ... <vn> <mem>
|
||||||
bool const encoderV2 = m_context.useABICoderV2();
|
bool const encoderV2 = m_context.useABICoderV2();
|
||||||
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
|
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
|
||||||
solAssert(targetTypes.size() == _givenTypes.size(), "");
|
solAssert(targetTypes.size() == _givenTypes.size());
|
||||||
for (Type const*& t: targetTypes)
|
for (Type const*& t: targetTypes)
|
||||||
{
|
{
|
||||||
Type const* tEncoding = t->fullEncodingType(_encodeAsLibraryTypes, encoderV2, !_padToWordBoundaries);
|
Type const* tEncoding = t->fullEncodingType(_encodeAsLibraryTypes, encoderV2, !_padToWordBoundaries);
|
||||||
@ -449,7 +449,7 @@ void CompilerUtils::encodeToMemory(
|
|||||||
);
|
);
|
||||||
auto stackHeightBefore = m_context.stackHeight();
|
auto stackHeightBefore = m_context.stackHeight();
|
||||||
abiEncodeV2(_givenTypes, targetTypes, _encodeAsLibraryTypes, _padToWordBoundaries);
|
abiEncodeV2(_givenTypes, targetTypes, _encodeAsLibraryTypes, _padToWordBoundaries);
|
||||||
solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes), "");
|
solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,8 +489,8 @@ void CompilerUtils::encodeToMemory(
|
|||||||
{
|
{
|
||||||
// special case: convert storage reference type to value type - this is only
|
// special case: convert storage reference type to value type - this is only
|
||||||
// possible for library calls where we just forward the storage reference
|
// possible for library calls where we just forward the storage reference
|
||||||
solAssert(_encodeAsLibraryTypes, "");
|
solAssert(_encodeAsLibraryTypes);
|
||||||
solAssert(_givenTypes[i]->sizeOnStack() == 1, "");
|
solAssert(_givenTypes[i]->sizeOnStack() == 1);
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
_givenTypes[i]->dataStoredIn(DataLocation::Storage) ||
|
_givenTypes[i]->dataStoredIn(DataLocation::Storage) ||
|
||||||
@ -638,7 +638,7 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
|
|||||||
{
|
{
|
||||||
if (_type.baseType()->hasSimpleZeroValueInMemory())
|
if (_type.baseType()->hasSimpleZeroValueInMemory())
|
||||||
{
|
{
|
||||||
solAssert(_type.baseType()->isValueType(), "");
|
solAssert(_type.baseType()->isValueType());
|
||||||
Whiskers templ(R"({
|
Whiskers templ(R"({
|
||||||
let size := mul(length, <element_size>)
|
let size := mul(length, <element_size>)
|
||||||
// cheap way of zero-initializing a memory range
|
// cheap way of zero-initializing a memory range
|
||||||
@ -774,9 +774,9 @@ void CompilerUtils::convertType(
|
|||||||
|
|
||||||
if (stackTypeCategory == Type::Category::UserDefinedValueType)
|
if (stackTypeCategory == Type::Category::UserDefinedValueType)
|
||||||
{
|
{
|
||||||
solAssert(_cleanupNeeded, "");
|
solAssert(_cleanupNeeded);
|
||||||
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(_typeOnStack);
|
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(_typeOnStack);
|
||||||
solAssert(_typeOnStack == _targetType || _targetType == userDefined.underlyingType(), "");
|
solAssert(_typeOnStack == _targetType || _targetType == userDefined.underlyingType());
|
||||||
return convertType(
|
return convertType(
|
||||||
userDefined.underlyingType(),
|
userDefined.underlyingType(),
|
||||||
_targetType,
|
_targetType,
|
||||||
@ -787,9 +787,9 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
if (targetTypeCategory == Type::Category::UserDefinedValueType)
|
if (targetTypeCategory == Type::Category::UserDefinedValueType)
|
||||||
{
|
{
|
||||||
solAssert(_cleanupNeeded, "");
|
solAssert(_cleanupNeeded);
|
||||||
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(_targetType);
|
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(_targetType);
|
||||||
solAssert(_typeOnStack.isImplicitlyConvertibleTo(userDefined.underlyingType()), "");
|
solAssert(_typeOnStack.isImplicitlyConvertibleTo(userDefined.underlyingType()));
|
||||||
return convertType(
|
return convertType(
|
||||||
_typeOnStack,
|
_typeOnStack,
|
||||||
userDefined.underlyingType(),
|
userDefined.underlyingType(),
|
||||||
@ -829,7 +829,7 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
else if (targetTypeCategory == Type::Category::Address)
|
else if (targetTypeCategory == Type::Category::Address)
|
||||||
{
|
{
|
||||||
solAssert(typeOnStack.numBytes() * 8 == 160, "");
|
solAssert(typeOnStack.numBytes() * 8 == 160);
|
||||||
rightShiftNumberOnStack(256 - 160);
|
rightShiftNumberOnStack(256 - 160);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -849,7 +849,7 @@ void CompilerUtils::convertType(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Enum:
|
case Type::Category::Enum:
|
||||||
solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, "");
|
solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer);
|
||||||
if (enumOverflowCheckPending)
|
if (enumOverflowCheckPending)
|
||||||
{
|
{
|
||||||
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack);
|
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack);
|
||||||
@ -885,13 +885,13 @@ void CompilerUtils::convertType(
|
|||||||
cleanHigherOrderBits(*typeOnStack);
|
cleanHigherOrderBits(*typeOnStack);
|
||||||
}
|
}
|
||||||
else if (stackTypeCategory == Type::Category::Address)
|
else if (stackTypeCategory == Type::Category::Address)
|
||||||
solAssert(targetBytesType.numBytes() * 8 == 160, "");
|
solAssert(targetBytesType.numBytes() * 8 == 160);
|
||||||
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
|
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
|
||||||
}
|
}
|
||||||
else if (targetTypeCategory == Type::Category::Enum)
|
else if (targetTypeCategory == Type::Category::Enum)
|
||||||
{
|
{
|
||||||
solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
|
solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
|
||||||
solAssert(_typeOnStack.mobileType(), "");
|
solAssert(_typeOnStack.mobileType());
|
||||||
// just clean
|
// just clean
|
||||||
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
||||||
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType);
|
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType);
|
||||||
@ -964,13 +964,13 @@ void CompilerUtils::convertType(
|
|||||||
if (targetTypeCategory == Type::Category::FixedBytes)
|
if (targetTypeCategory == Type::Category::FixedBytes)
|
||||||
{
|
{
|
||||||
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(_targetType).numBytes();
|
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(_targetType).numBytes();
|
||||||
solAssert(data.size() <= 32, "");
|
solAssert(data.size() <= 32);
|
||||||
m_context << (u256(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes))));
|
m_context << (u256(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes))));
|
||||||
}
|
}
|
||||||
else if (targetTypeCategory == Type::Category::Array)
|
else if (targetTypeCategory == Type::Category::Array)
|
||||||
{
|
{
|
||||||
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
|
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
|
||||||
solAssert(arrayType.isByteArray(), "");
|
solAssert(arrayType.isByteArray());
|
||||||
size_t storageSize = 32 + ((data.size() + 31) / 32) * 32;
|
size_t storageSize = 32 + ((data.size() + 31) / 32) * 32;
|
||||||
allocateMemory(storageSize);
|
allocateMemory(storageSize);
|
||||||
// stack: mempos
|
// stack: mempos
|
||||||
@ -995,10 +995,10 @@ void CompilerUtils::convertType(
|
|||||||
typeOnStack.isByteArray() && !typeOnStack.isString(),
|
typeOnStack.isByteArray() && !typeOnStack.isString(),
|
||||||
"Array types other than bytes not convertible to bytesNN."
|
"Array types other than bytes not convertible to bytesNN."
|
||||||
);
|
);
|
||||||
solAssert(typeOnStack.isDynamicallySized(), "");
|
solAssert(typeOnStack.isDynamicallySized());
|
||||||
|
|
||||||
bool fromCalldata = typeOnStack.dataStoredIn(DataLocation::CallData);
|
bool fromCalldata = typeOnStack.dataStoredIn(DataLocation::CallData);
|
||||||
solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1), "");
|
solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1));
|
||||||
if (fromCalldata)
|
if (fromCalldata)
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
|
|
||||||
@ -1012,7 +1012,7 @@ void CompilerUtils::convertType(
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
solAssert(targetTypeCategory == stackTypeCategory, "");
|
solAssert(targetTypeCategory == stackTypeCategory);
|
||||||
auto const& targetType = dynamic_cast<ArrayType const&>(_targetType);
|
auto const& targetType = dynamic_cast<ArrayType const&>(_targetType);
|
||||||
switch (targetType.location())
|
switch (targetType.location())
|
||||||
{
|
{
|
||||||
@ -1034,9 +1034,9 @@ void CompilerUtils::convertType(
|
|||||||
typeOnStack.baseType()->isDynamicallyEncoded()
|
typeOnStack.baseType()->isDynamicallyEncoded()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(m_context.useABICoderV2(), "");
|
solAssert(m_context.useABICoderV2());
|
||||||
// stack: offset length(optional in case of dynamically sized array)
|
// stack: offset length(optional in case of dynamically sized array)
|
||||||
solAssert(typeOnStack.sizeOnStack() == (typeOnStack.isDynamicallySized() ? 2 : 1), "");
|
solAssert(typeOnStack.sizeOnStack() == (typeOnStack.isDynamicallySized() ? 2 : 1));
|
||||||
if (typeOnStack.isDynamicallySized())
|
if (typeOnStack.isDynamicallySized())
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
|
|
||||||
@ -1122,9 +1122,9 @@ void CompilerUtils::convertType(
|
|||||||
typeOnStack.arrayType().isByteArray() && !typeOnStack.arrayType().isString(),
|
typeOnStack.arrayType().isByteArray() && !typeOnStack.arrayType().isString(),
|
||||||
"Array types other than bytes not convertible to bytesNN."
|
"Array types other than bytes not convertible to bytesNN."
|
||||||
);
|
);
|
||||||
solAssert(typeOnStack.isDynamicallySized(), "");
|
solAssert(typeOnStack.isDynamicallySized());
|
||||||
solAssert(typeOnStack.dataStoredIn(DataLocation::CallData), "");
|
solAssert(typeOnStack.dataStoredIn(DataLocation::CallData));
|
||||||
solAssert(typeOnStack.sizeOnStack() == 2, "");
|
solAssert(typeOnStack.sizeOnStack() == 2);
|
||||||
|
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
m_context.callYulFunction(
|
m_context.callYulFunction(
|
||||||
@ -1138,14 +1138,16 @@ void CompilerUtils::convertType(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
solAssert(_targetType.category() == Type::Category::Array, "");
|
solAssert(_targetType.category() == Type::Category::Array);
|
||||||
auto const& targetArrayType = dynamic_cast<ArrayType const&>(_targetType);
|
auto const& targetArrayType = dynamic_cast<ArrayType const&>(_targetType);
|
||||||
solAssert(typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType), "");
|
solAssert(
|
||||||
|
typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType) ||
|
||||||
|
(typeOnStack.arrayType().isByteArray() && targetArrayType.isByteArray())
|
||||||
|
);
|
||||||
solAssert(
|
solAssert(
|
||||||
typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) &&
|
typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) &&
|
||||||
typeOnStack.arrayType().isDynamicallySized() &&
|
typeOnStack.arrayType().isDynamicallySized() &&
|
||||||
!typeOnStack.arrayType().baseType()->isDynamicallyEncoded(),
|
!typeOnStack.arrayType().baseType()->isDynamicallyEncoded()
|
||||||
""
|
|
||||||
);
|
);
|
||||||
if (!_targetType.dataStoredIn(DataLocation::CallData))
|
if (!_targetType.dataStoredIn(DataLocation::CallData))
|
||||||
return convertType(typeOnStack.arrayType(), _targetType);
|
return convertType(typeOnStack.arrayType(), _targetType);
|
||||||
@ -1153,7 +1155,7 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
case Type::Category::Struct:
|
case Type::Category::Struct:
|
||||||
{
|
{
|
||||||
solAssert(targetTypeCategory == stackTypeCategory, "");
|
solAssert(targetTypeCategory == stackTypeCategory);
|
||||||
auto& targetType = dynamic_cast<StructType const&>(_targetType);
|
auto& targetType = dynamic_cast<StructType const&>(_targetType);
|
||||||
auto& typeOnStack = dynamic_cast<StructType const&>(_typeOnStack);
|
auto& typeOnStack = dynamic_cast<StructType const&>(_typeOnStack);
|
||||||
switch (targetType.location())
|
switch (targetType.location())
|
||||||
@ -1182,7 +1184,7 @@ void CompilerUtils::convertType(
|
|||||||
// stack: <memory ptr> <source ref> <memory ptr>
|
// stack: <memory ptr> <source ref> <memory ptr>
|
||||||
for (auto const& member: typeOnStack->members(nullptr))
|
for (auto const& member: typeOnStack->members(nullptr))
|
||||||
{
|
{
|
||||||
solAssert(!member.type->containsNestedMapping(), "");
|
solAssert(!member.type->containsNestedMapping());
|
||||||
pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name);
|
pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name);
|
||||||
_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
|
_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
|
||||||
_context << u256(offsets.second);
|
_context << u256(offsets.second);
|
||||||
@ -1209,7 +1211,7 @@ void CompilerUtils::convertType(
|
|||||||
{
|
{
|
||||||
if (typeOnStack.isDynamicallyEncoded())
|
if (typeOnStack.isDynamicallyEncoded())
|
||||||
{
|
{
|
||||||
solAssert(m_context.useABICoderV2(), "");
|
solAssert(m_context.useABICoderV2());
|
||||||
m_context.callYulFunction(
|
m_context.callYulFunction(
|
||||||
m_context.utilFunctions().conversionFunction(typeOnStack, targetType),
|
m_context.utilFunctions().conversionFunction(typeOnStack, targetType),
|
||||||
1,
|
1,
|
||||||
@ -1231,7 +1233,7 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
solAssert(_typeOnStack == _targetType, "");
|
solAssert(_typeOnStack == _targetType);
|
||||||
// nothing to do
|
// nothing to do
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1241,7 +1243,7 @@ void CompilerUtils::convertType(
|
|||||||
{
|
{
|
||||||
TupleType const& sourceTuple = dynamic_cast<TupleType const&>(_typeOnStack);
|
TupleType const& sourceTuple = dynamic_cast<TupleType const&>(_typeOnStack);
|
||||||
TupleType const& targetTuple = dynamic_cast<TupleType const&>(_targetType);
|
TupleType const& targetTuple = dynamic_cast<TupleType const&>(_targetType);
|
||||||
solAssert(targetTuple.components().size() == sourceTuple.components().size(), "");
|
solAssert(targetTuple.components().size() == sourceTuple.components().size());
|
||||||
unsigned depth = sourceTuple.sizeOnStack();
|
unsigned depth = sourceTuple.sizeOnStack();
|
||||||
for (size_t i = 0; i < sourceTuple.components().size(); ++i)
|
for (size_t i = 0; i < sourceTuple.components().size(); ++i)
|
||||||
{
|
{
|
||||||
@ -1249,7 +1251,7 @@ void CompilerUtils::convertType(
|
|||||||
Type const* targetType = targetTuple.components()[i];
|
Type const* targetType = targetTuple.components()[i];
|
||||||
if (!sourceType)
|
if (!sourceType)
|
||||||
{
|
{
|
||||||
solAssert(!targetType, "");
|
solAssert(!targetType);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
unsigned sourceSize = sourceType->sizeOnStack();
|
unsigned sourceSize = sourceType->sizeOnStack();
|
||||||
@ -1291,7 +1293,7 @@ void CompilerUtils::convertType(
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// we used to allow conversions from function to address
|
// we used to allow conversions from function to address
|
||||||
solAssert(!(stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address), "");
|
solAssert(!(stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address));
|
||||||
if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function)
|
if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function)
|
||||||
{
|
{
|
||||||
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
||||||
@ -1348,14 +1350,14 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
|||||||
}
|
}
|
||||||
if (referenceType->location() == DataLocation::CallData)
|
if (referenceType->location() == DataLocation::CallData)
|
||||||
{
|
{
|
||||||
solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2, "");
|
solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2);
|
||||||
m_context << Instruction::CALLDATASIZE;
|
m_context << Instruction::CALLDATASIZE;
|
||||||
if (referenceType->sizeOnStack() == 2)
|
if (referenceType->sizeOnStack() == 2)
|
||||||
m_context << 0;
|
m_context << 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
solAssert(referenceType->location() == DataLocation::Memory, "");
|
solAssert(referenceType->location() == DataLocation::Memory);
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||||
if (arrayType->isDynamicallySized())
|
if (arrayType->isDynamicallySized())
|
||||||
{
|
{
|
||||||
@ -1383,7 +1385,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
|||||||
}
|
}
|
||||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
else if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
||||||
{
|
{
|
||||||
solAssert(!arrayType->isDynamicallySized(), "");
|
solAssert(!arrayType->isDynamicallySized());
|
||||||
if (arrayType->length() > 0)
|
if (arrayType->length() > 0)
|
||||||
{
|
{
|
||||||
_context << arrayType->length() << Instruction::SWAP1;
|
_context << arrayType->length() << Instruction::SWAP1;
|
||||||
@ -1483,7 +1485,7 @@ void CompilerUtils::popStackSlots(size_t _amount)
|
|||||||
|
|
||||||
void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _jumpTo)
|
void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _jumpTo)
|
||||||
{
|
{
|
||||||
solAssert(m_context.stackHeight() >= _toHeight, "");
|
solAssert(m_context.stackHeight() >= _toHeight);
|
||||||
unsigned amount = m_context.stackHeight() - _toHeight;
|
unsigned amount = m_context.stackHeight() - _toHeight;
|
||||||
popStackSlots(amount);
|
popStackSlots(amount);
|
||||||
m_context.appendJumpTo(_jumpTo);
|
m_context.appendJumpTo(_jumpTo);
|
||||||
@ -1551,7 +1553,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
|
|||||||
|
|
||||||
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords)
|
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords)
|
||||||
{
|
{
|
||||||
solAssert(_type.isValueType(), "");
|
solAssert(_type.isValueType());
|
||||||
Type const* type = &_type;
|
Type const* type = &_type;
|
||||||
if (auto const* userDefined = dynamic_cast<UserDefinedValueType const*>(type))
|
if (auto const* userDefined = dynamic_cast<UserDefinedValueType const*>(type))
|
||||||
type = &userDefined->underlyingType();
|
type = &userDefined->underlyingType();
|
||||||
@ -1603,7 +1605,7 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
|
|||||||
|
|
||||||
void CompilerUtils::leftShiftNumberOnStack(unsigned _bits)
|
void CompilerUtils::leftShiftNumberOnStack(unsigned _bits)
|
||||||
{
|
{
|
||||||
solAssert(_bits < 256, "");
|
solAssert(_bits < 256);
|
||||||
if (m_context.evmVersion().hasBitwiseShifting())
|
if (m_context.evmVersion().hasBitwiseShifting())
|
||||||
m_context << _bits << Instruction::SHL;
|
m_context << _bits << Instruction::SHL;
|
||||||
else
|
else
|
||||||
@ -1612,7 +1614,7 @@ void CompilerUtils::leftShiftNumberOnStack(unsigned _bits)
|
|||||||
|
|
||||||
void CompilerUtils::rightShiftNumberOnStack(unsigned _bits)
|
void CompilerUtils::rightShiftNumberOnStack(unsigned _bits)
|
||||||
{
|
{
|
||||||
solAssert(_bits < 256, "");
|
solAssert(_bits < 256);
|
||||||
// NOTE: If we add signed right shift, SAR rounds differently than SDIV
|
// NOTE: If we add signed right shift, SAR rounds differently than SDIV
|
||||||
if (m_context.evmVersion().hasBitwiseShifting())
|
if (m_context.evmVersion().hasBitwiseShifting())
|
||||||
m_context << _bits << Instruction::SHR;
|
m_context << _bits << Instruction::SHR;
|
||||||
@ -1627,7 +1629,7 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords,
|
|||||||
"Memory store of types with stack size != 1 not allowed (Type: " + _type.toString(true) + ")."
|
"Memory store of types with stack size != 1 not allowed (Type: " + _type.toString(true) + ")."
|
||||||
);
|
);
|
||||||
|
|
||||||
solAssert(!_type.isDynamicallyEncoded(), "");
|
solAssert(!_type.isDynamicallyEncoded());
|
||||||
|
|
||||||
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
|
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
|
||||||
|
|
||||||
|
@ -3219,15 +3219,17 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN.");
|
solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN.");
|
||||||
return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast<FixedBytesType const &>(_to));
|
return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast<FixedBytesType const &>(_to));
|
||||||
}
|
}
|
||||||
solAssert(_to.category() == Type::Category::Array, "");
|
solAssert(_to.category() == Type::Category::Array);
|
||||||
auto const& targetType = dynamic_cast<ArrayType const&>(_to);
|
auto const& targetType = dynamic_cast<ArrayType const&>(_to);
|
||||||
|
|
||||||
solAssert(fromType.arrayType().isImplicitlyConvertibleTo(targetType), "");
|
solAssert(
|
||||||
|
fromType.arrayType().isImplicitlyConvertibleTo(targetType) ||
|
||||||
|
(fromType.arrayType().isByteArray() && targetType.isByteArray())
|
||||||
|
);
|
||||||
solAssert(
|
solAssert(
|
||||||
fromType.arrayType().dataStoredIn(DataLocation::CallData) &&
|
fromType.arrayType().dataStoredIn(DataLocation::CallData) &&
|
||||||
fromType.arrayType().isDynamicallySized() &&
|
fromType.arrayType().isDynamicallySized() &&
|
||||||
!fromType.arrayType().baseType()->isDynamicallyEncoded(),
|
!fromType.arrayType().baseType()->isDynamicallyEncoded()
|
||||||
""
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!targetType.dataStoredIn(DataLocation::CallData))
|
if (!targetType.dataStoredIn(DataLocation::CallData))
|
||||||
|
@ -95,7 +95,7 @@ struct CopyTranslate: public yul::ASTCopier
|
|||||||
return ASTCopier::translate(_identifier);
|
return ASTCopier::translate(_identifier);
|
||||||
|
|
||||||
yul::Expression translated = translateReference(_identifier);
|
yul::Expression translated = translateReference(_identifier);
|
||||||
solAssert(holds_alternative<yul::Identifier>(translated), "");
|
solAssert(holds_alternative<yul::Identifier>(translated));
|
||||||
return get<yul::Identifier>(std::move(translated));
|
return get<yul::Identifier>(std::move(translated));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,14 +115,14 @@ private:
|
|||||||
if (suffix.empty() && varDecl->isLocalVariable())
|
if (suffix.empty() && varDecl->isLocalVariable())
|
||||||
{
|
{
|
||||||
auto const& var = m_context.localVariable(*varDecl);
|
auto const& var = m_context.localVariable(*varDecl);
|
||||||
solAssert(var.type().sizeOnStack() == 1, "");
|
solAssert(var.type().sizeOnStack() == 1);
|
||||||
|
|
||||||
value = var.commaSeparatedList();
|
value = var.commaSeparatedList();
|
||||||
}
|
}
|
||||||
else if (varDecl->isConstant())
|
else if (varDecl->isConstant())
|
||||||
{
|
{
|
||||||
VariableDeclaration const* variable = rootConstVariableDeclaration(*varDecl);
|
VariableDeclaration const* variable = rootConstVariableDeclaration(*varDecl);
|
||||||
solAssert(variable, "");
|
solAssert(variable);
|
||||||
|
|
||||||
if (variable->value()->annotation().type->category() == Type::Category::RationalNumber)
|
if (variable->value()->annotation().type->category() == Type::Category::RationalNumber)
|
||||||
{
|
{
|
||||||
@ -130,7 +130,7 @@ private:
|
|||||||
if (auto const* bytesType = dynamic_cast<FixedBytesType const*>(variable->type()))
|
if (auto const* bytesType = dynamic_cast<FixedBytesType const*>(variable->type()))
|
||||||
intValue <<= 256 - 8 * bytesType->numBytes();
|
intValue <<= 256 - 8 * bytesType->numBytes();
|
||||||
else
|
else
|
||||||
solAssert(variable->type()->category() == Type::Category::Integer, "");
|
solAssert(variable->type()->category() == Type::Category::Integer);
|
||||||
value = intValue.str();
|
value = intValue.str();
|
||||||
}
|
}
|
||||||
else if (auto const* literal = dynamic_cast<Literal const*>(variable->value().get()))
|
else if (auto const* literal = dynamic_cast<Literal const*>(variable->value().get()))
|
||||||
@ -141,20 +141,20 @@ private:
|
|||||||
{
|
{
|
||||||
case Type::Category::Bool:
|
case Type::Category::Bool:
|
||||||
case Type::Category::Address:
|
case Type::Category::Address:
|
||||||
solAssert(type->category() == variable->annotation().type->category(), "");
|
solAssert(type->category() == variable->annotation().type->category());
|
||||||
value = toCompactHexWithPrefix(type->literalValue(literal));
|
value = toCompactHexWithPrefix(type->literalValue(literal));
|
||||||
break;
|
break;
|
||||||
case Type::Category::StringLiteral:
|
case Type::Category::StringLiteral:
|
||||||
{
|
{
|
||||||
auto const& stringLiteral = dynamic_cast<StringLiteralType const&>(*type);
|
auto const& stringLiteral = dynamic_cast<StringLiteralType const&>(*type);
|
||||||
solAssert(variable->type()->category() == Type::Category::FixedBytes, "");
|
solAssert(variable->type()->category() == Type::Category::FixedBytes);
|
||||||
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(*variable->type()).numBytes();
|
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(*variable->type()).numBytes();
|
||||||
solAssert(stringLiteral.value().size() <= numBytes, "");
|
solAssert(stringLiteral.value().size() <= numBytes);
|
||||||
value = formatNumber(u256(h256(stringLiteral.value(), h256::AlignLeft)));
|
value = formatNumber(u256(h256(stringLiteral.value(), h256::AlignLeft)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
solAssert(false, "");
|
solAssert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -167,25 +167,25 @@ private:
|
|||||||
else if (suffix == "offset")
|
else if (suffix == "offset")
|
||||||
value = to_string(m_context.storageLocationOfStateVariable(*varDecl).second);
|
value = to_string(m_context.storageLocationOfStateVariable(*varDecl).second);
|
||||||
else
|
else
|
||||||
solAssert(false, "");
|
solAssert(false);
|
||||||
}
|
}
|
||||||
else if (varDecl->type()->dataStoredIn(DataLocation::Storage))
|
else if (varDecl->type()->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
solAssert(suffix == "slot" || suffix == "offset", "");
|
solAssert(suffix == "slot" || suffix == "offset");
|
||||||
solAssert(varDecl->isLocalVariable(), "");
|
solAssert(varDecl->isLocalVariable());
|
||||||
if (suffix == "slot")
|
if (suffix == "slot")
|
||||||
value = IRVariable{*varDecl}.part("slot").name();
|
value = IRVariable{*varDecl}.part("slot").name();
|
||||||
else if (varDecl->type()->isValueType())
|
else if (varDecl->type()->isValueType())
|
||||||
value = IRVariable{*varDecl}.part("offset").name();
|
value = IRVariable{*varDecl}.part("offset").name();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(!IRVariable{*varDecl}.hasPart("offset"), "");
|
solAssert(!IRVariable{*varDecl}.hasPart("offset"));
|
||||||
value = "0";
|
value = "0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (varDecl->type()->dataStoredIn(DataLocation::CallData))
|
else if (varDecl->type()->dataStoredIn(DataLocation::CallData))
|
||||||
{
|
{
|
||||||
solAssert(suffix == "offset" || suffix == "length", "");
|
solAssert(suffix == "offset" || suffix == "length");
|
||||||
value = IRVariable{*varDecl}.part(suffix).name();
|
value = IRVariable{*varDecl}.part(suffix).name();
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
@ -193,15 +193,15 @@ private:
|
|||||||
functionType && functionType->kind() == FunctionType::Kind::External
|
functionType && functionType->kind() == FunctionType::Kind::External
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(suffix == "selector" || suffix == "address", "");
|
solAssert(suffix == "selector" || suffix == "address");
|
||||||
solAssert(varDecl->type()->sizeOnStack() == 2, "");
|
solAssert(varDecl->type()->sizeOnStack() == 2);
|
||||||
if (suffix == "selector")
|
if (suffix == "selector")
|
||||||
value = IRVariable{*varDecl}.part("functionSelector").name();
|
value = IRVariable{*varDecl}.part("functionSelector").name();
|
||||||
else
|
else
|
||||||
value = IRVariable{*varDecl}.part("address").name();
|
value = IRVariable{*varDecl}.part("address").name();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(false, "");
|
solAssert(false);
|
||||||
|
|
||||||
if (isdigit(value.front()))
|
if (isdigit(value.front()))
|
||||||
return yul::Literal{_identifier.debugData, yul::LiteralKind::Number, yul::YulString{value}, {}};
|
return yul::Literal{_identifier.debugData, yul::LiteralKind::Number, yul::YulString{value}, {}};
|
||||||
@ -268,7 +268,7 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va
|
|||||||
setLocation(_varDecl);
|
setLocation(_varDecl);
|
||||||
|
|
||||||
solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable.");
|
solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable.");
|
||||||
solAssert(!_varDecl.isConstant(), "");
|
solAssert(!_varDecl.isConstant());
|
||||||
if (!_varDecl.value())
|
if (!_varDecl.value())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -355,7 +355,7 @@ string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const
|
|||||||
templ("sourceLocationComment", dispenseLocationComment(_constant, m_context));
|
templ("sourceLocationComment", dispenseLocationComment(_constant, m_context));
|
||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
IRGeneratorForStatements generator(m_context, m_utils);
|
IRGeneratorForStatements generator(m_context, m_utils);
|
||||||
solAssert(_constant.value(), "");
|
solAssert(_constant.value());
|
||||||
Type const& constantType = *_constant.type();
|
Type const& constantType = *_constant.type();
|
||||||
templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList());
|
templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList());
|
||||||
templ("code", generator.code());
|
templ("code", generator.code());
|
||||||
@ -386,7 +386,7 @@ void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _var
|
|||||||
for (size_t i = 0; i < _varDeclStatement.declarations().size(); ++i)
|
for (size_t i = 0; i < _varDeclStatement.declarations().size(); ++i)
|
||||||
if (auto const& decl = _varDeclStatement.declarations()[i])
|
if (auto const& decl = _varDeclStatement.declarations()[i])
|
||||||
{
|
{
|
||||||
solAssert(tupleType->components()[i], "");
|
solAssert(tupleType->components()[i]);
|
||||||
define(m_context.addLocalVariable(*decl), IRVariable(*expression).tupleComponent(i));
|
define(m_context.addLocalVariable(*decl), IRVariable(*expression).tupleComponent(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,7 +443,7 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
|||||||
TokenTraits::AssignmentToBinaryOp(assignmentOperator);
|
TokenTraits::AssignmentToBinaryOp(assignmentOperator);
|
||||||
|
|
||||||
if (TokenTraits::isShiftOp(binaryOperator))
|
if (TokenTraits::isShiftOp(binaryOperator))
|
||||||
solAssert(type(_assignment.rightHandSide()).mobileType(), "");
|
solAssert(type(_assignment.rightHandSide()).mobileType());
|
||||||
IRVariable value =
|
IRVariable value =
|
||||||
type(_assignment.leftHandSide()).isValueType() ?
|
type(_assignment.leftHandSide()).isValueType() ?
|
||||||
convert(
|
convert(
|
||||||
@ -460,11 +460,11 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
|||||||
if (assignmentOperator != Token::Assign)
|
if (assignmentOperator != Token::Assign)
|
||||||
{
|
{
|
||||||
solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types.");
|
solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types.");
|
||||||
solAssert(binaryOperator != Token::Exp, "");
|
solAssert(binaryOperator != Token::Exp);
|
||||||
solAssert(type(_assignment) == type(_assignment.leftHandSide()), "");
|
solAssert(type(_assignment) == type(_assignment.leftHandSide()));
|
||||||
|
|
||||||
IRVariable leftIntermediate = readFromLValue(*m_currentLValue);
|
IRVariable leftIntermediate = readFromLValue(*m_currentLValue);
|
||||||
solAssert(type(_assignment) == leftIntermediate.type(), "");
|
solAssert(type(_assignment) == leftIntermediate.type());
|
||||||
|
|
||||||
define(_assignment) << (
|
define(_assignment) << (
|
||||||
TokenTraits::isShiftOp(binaryOperator) ?
|
TokenTraits::isShiftOp(binaryOperator) ?
|
||||||
@ -523,14 +523,14 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
|||||||
{
|
{
|
||||||
bool willBeWrittenTo = _tuple.annotation().willBeWrittenTo;
|
bool willBeWrittenTo = _tuple.annotation().willBeWrittenTo;
|
||||||
if (willBeWrittenTo)
|
if (willBeWrittenTo)
|
||||||
solAssert(!m_currentLValue, "");
|
solAssert(!m_currentLValue);
|
||||||
if (_tuple.components().size() == 1)
|
if (_tuple.components().size() == 1)
|
||||||
{
|
{
|
||||||
solAssert(_tuple.components().front(), "");
|
solAssert(_tuple.components().front());
|
||||||
_tuple.components().front()->accept(*this);
|
_tuple.components().front()->accept(*this);
|
||||||
setLocation(_tuple);
|
setLocation(_tuple);
|
||||||
if (willBeWrittenTo)
|
if (willBeWrittenTo)
|
||||||
solAssert(!!m_currentLValue, "");
|
solAssert(!!m_currentLValue);
|
||||||
else
|
else
|
||||||
define(_tuple, *_tuple.components().front());
|
define(_tuple, *_tuple.components().front());
|
||||||
}
|
}
|
||||||
@ -544,7 +544,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
|||||||
setLocation(_tuple);
|
setLocation(_tuple);
|
||||||
if (willBeWrittenTo)
|
if (willBeWrittenTo)
|
||||||
{
|
{
|
||||||
solAssert(!!m_currentLValue, "");
|
solAssert(!!m_currentLValue);
|
||||||
lvalues.emplace_back(std::move(m_currentLValue));
|
lvalues.emplace_back(std::move(m_currentLValue));
|
||||||
m_currentLValue.reset();
|
m_currentLValue.reset();
|
||||||
}
|
}
|
||||||
@ -568,7 +568,7 @@ bool IRGeneratorForStatements::visit(Block const& _block)
|
|||||||
{
|
{
|
||||||
if (_block.unchecked())
|
if (_block.unchecked())
|
||||||
{
|
{
|
||||||
solAssert(m_context.arithmetic() == Arithmetic::Checked, "");
|
solAssert(m_context.arithmetic() == Arithmetic::Checked);
|
||||||
m_context.setArithmetic(Arithmetic::Wrapping);
|
m_context.setArithmetic(Arithmetic::Wrapping);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -578,7 +578,7 @@ void IRGeneratorForStatements::endVisit(Block const& _block)
|
|||||||
{
|
{
|
||||||
if (_block.unchecked())
|
if (_block.unchecked())
|
||||||
{
|
{
|
||||||
solAssert(m_context.arithmetic() == Arithmetic::Wrapping, "");
|
solAssert(m_context.arithmetic() == Arithmetic::Wrapping);
|
||||||
m_context.setArithmetic(Arithmetic::Checked);
|
m_context.setArithmetic(Arithmetic::Checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -607,7 +607,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
|||||||
|
|
||||||
void IRGeneratorForStatements::endVisit(PlaceholderStatement const& _placeholder)
|
void IRGeneratorForStatements::endVisit(PlaceholderStatement const& _placeholder)
|
||||||
{
|
{
|
||||||
solAssert(m_placeholderCallback, "");
|
solAssert(m_placeholderCallback);
|
||||||
setLocation(_placeholder);
|
setLocation(_placeholder);
|
||||||
appendCode() << m_placeholderCallback();
|
appendCode() << m_placeholderCallback();
|
||||||
}
|
}
|
||||||
@ -776,7 +776,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
|||||||
{
|
{
|
||||||
setLocation(_binOp);
|
setLocation(_binOp);
|
||||||
|
|
||||||
solAssert(!!_binOp.annotation().commonType, "");
|
solAssert(!!_binOp.annotation().commonType);
|
||||||
Type const* commonType = _binOp.annotation().commonType;
|
Type const* commonType = _binOp.annotation().commonType;
|
||||||
langutil::Token op = _binOp.getOperator();
|
langutil::Token op = _binOp.getOperator();
|
||||||
|
|
||||||
@ -799,7 +799,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
|||||||
|
|
||||||
if (TokenTraits::isCompareOp(op))
|
if (TokenTraits::isCompareOp(op))
|
||||||
{
|
{
|
||||||
solAssert(commonType->isValueType(), "");
|
solAssert(commonType->isValueType());
|
||||||
|
|
||||||
bool isSigned = false;
|
bool isSigned = false;
|
||||||
if (auto type = dynamic_cast<IntegerType const*>(commonType))
|
if (auto type = dynamic_cast<IntegerType const*>(commonType))
|
||||||
@ -855,7 +855,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
|||||||
else if (auto rationalNumberType = dynamic_cast<RationalNumberType const*>(_binOp.leftExpression().annotation().type))
|
else if (auto rationalNumberType = dynamic_cast<RationalNumberType const*>(_binOp.leftExpression().annotation().type))
|
||||||
{
|
{
|
||||||
solAssert(rationalNumberType->integerType(), "Invalid literal as the base for exponentiation.");
|
solAssert(rationalNumberType->integerType(), "Invalid literal as the base for exponentiation.");
|
||||||
solAssert(dynamic_cast<IntegerType const*>(commonType), "");
|
solAssert(dynamic_cast<IntegerType const*>(commonType));
|
||||||
|
|
||||||
define(_binOp) << m_utils.overflowCheckedIntLiteralExpFunction(
|
define(_binOp) << m_utils.overflowCheckedIntLiteralExpFunction(
|
||||||
*rationalNumberType,
|
*rationalNumberType,
|
||||||
@ -951,7 +951,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
FunctionDefinition const* functionDef = ASTNode::resolveFunctionCall(_functionCall, &m_context.mostDerivedContract());
|
FunctionDefinition const* functionDef = ASTNode::resolveFunctionCall(_functionCall, &m_context.mostDerivedContract());
|
||||||
|
|
||||||
solAssert(!functionType->takesArbitraryParameters(), "");
|
solAssert(!functionType->takesArbitraryParameters());
|
||||||
|
|
||||||
vector<string> args;
|
vector<string> args;
|
||||||
if (functionType->bound())
|
if (functionType->bound())
|
||||||
@ -962,7 +962,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
if (functionDef)
|
if (functionDef)
|
||||||
{
|
{
|
||||||
solAssert(functionDef->isImplemented(), "");
|
solAssert(functionDef->isImplemented());
|
||||||
|
|
||||||
define(_functionCall) <<
|
define(_functionCall) <<
|
||||||
m_context.enqueueFunctionForCodeGeneration(*functionDef) <<
|
m_context.enqueueFunctionForCodeGeneration(*functionDef) <<
|
||||||
@ -1065,7 +1065,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::Error:
|
case FunctionType::Kind::Error:
|
||||||
{
|
{
|
||||||
ErrorDefinition const* error = dynamic_cast<ErrorDefinition const*>(ASTNode::referencedDeclaration(_functionCall.expression()));
|
ErrorDefinition const* error = dynamic_cast<ErrorDefinition const*>(ASTNode::referencedDeclaration(_functionCall.expression()));
|
||||||
solAssert(error, "");
|
solAssert(error);
|
||||||
revertWithError(
|
revertWithError(
|
||||||
error->functionType(true)->externalSignature(),
|
error->functionType(true)->externalSignature(),
|
||||||
error->functionType(true)->parameterTypes(),
|
error->functionType(true)->parameterTypes(),
|
||||||
@ -1076,7 +1076,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::Wrap:
|
case FunctionType::Kind::Wrap:
|
||||||
case FunctionType::Kind::Unwrap:
|
case FunctionType::Kind::Unwrap:
|
||||||
{
|
{
|
||||||
solAssert(arguments.size() == 1, "");
|
solAssert(arguments.size() == 1);
|
||||||
FunctionType::Kind kind = functionType->kind();
|
FunctionType::Kind kind = functionType->kind();
|
||||||
if (kind == FunctionType::Kind::Wrap)
|
if (kind == FunctionType::Kind::Wrap)
|
||||||
solAssert(
|
solAssert(
|
||||||
@ -1086,7 +1086,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
""
|
""
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
solAssert(type(*arguments.at(0)).category() == Type::Category::UserDefinedValueType, "");
|
solAssert(type(*arguments.at(0)).category() == Type::Category::UserDefinedValueType);
|
||||||
|
|
||||||
define(_functionCall, *arguments.at(0));
|
define(_functionCall, *arguments.at(0));
|
||||||
break;
|
break;
|
||||||
@ -1120,7 +1120,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::ABIEncodeWithSignature:
|
case FunctionType::Kind::ABIEncodeWithSignature:
|
||||||
{
|
{
|
||||||
bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked;
|
bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked;
|
||||||
solAssert(functionType->padArguments() != isPacked, "");
|
solAssert(functionType->padArguments() != isPacked);
|
||||||
bool const hasSelectorOrSignature =
|
bool const hasSelectorOrSignature =
|
||||||
functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector ||
|
functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector ||
|
||||||
functionType->kind() == FunctionType::Kind::ABIEncodeCall ||
|
functionType->kind() == FunctionType::Kind::ABIEncodeCall ||
|
||||||
@ -1134,7 +1134,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
|
if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
|
||||||
{
|
{
|
||||||
solAssert(arguments.size() == 2, "");
|
solAssert(arguments.size() == 2);
|
||||||
// Account for tuples with one component which become that component
|
// Account for tuples with one component which become that component
|
||||||
if (type(*arguments[1]).category() == Type::Category::Tuple)
|
if (type(*arguments[1]).category() == Type::Category::Tuple)
|
||||||
{
|
{
|
||||||
@ -1257,7 +1257,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
referenceType && referenceType->dataStoredIn(DataLocation::CallData)
|
referenceType && referenceType->dataStoredIn(DataLocation::CallData)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(referenceType->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata()), "");
|
solAssert(referenceType->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata()));
|
||||||
IRVariable var = convert(*arguments[0], *TypeProvider::bytesCalldata());
|
IRVariable var = convert(*arguments[0], *TypeProvider::bytesCalldata());
|
||||||
templ("abiDecode", m_context.abiFunctions().tupleDecoder(targetTypes, false));
|
templ("abiDecode", m_context.abiFunctions().tupleDecoder(targetTypes, false));
|
||||||
templ("offset", var.part("offset").name());
|
templ("offset", var.part("offset").name());
|
||||||
@ -1279,8 +1279,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
}
|
}
|
||||||
case FunctionType::Kind::Revert:
|
case FunctionType::Kind::Revert:
|
||||||
{
|
{
|
||||||
solAssert(arguments.size() == parameterTypes.size(), "");
|
solAssert(arguments.size() == parameterTypes.size());
|
||||||
solAssert(arguments.size() <= 1, "");
|
solAssert(arguments.size() <= 1);
|
||||||
solAssert(
|
solAssert(
|
||||||
arguments.empty() ||
|
arguments.empty() ||
|
||||||
arguments.front()->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),
|
arguments.front()->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),
|
||||||
@ -1299,7 +1299,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::ObjectCreation:
|
case FunctionType::Kind::ObjectCreation:
|
||||||
{
|
{
|
||||||
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_functionCall.annotation().type);
|
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_functionCall.annotation().type);
|
||||||
solAssert(arguments.size() == 1, "");
|
solAssert(arguments.size() == 1);
|
||||||
|
|
||||||
IRVariable value = convert(*arguments[0], *TypeProvider::uint256());
|
IRVariable value = convert(*arguments[0], *TypeProvider::uint256());
|
||||||
define(_functionCall) <<
|
define(_functionCall) <<
|
||||||
@ -1311,7 +1311,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
}
|
}
|
||||||
case FunctionType::Kind::KECCAK256:
|
case FunctionType::Kind::KECCAK256:
|
||||||
{
|
{
|
||||||
solAssert(arguments.size() == 1, "");
|
solAssert(arguments.size() == 1);
|
||||||
|
|
||||||
ArrayType const* arrayType = TypeProvider::bytesMemory();
|
ArrayType const* arrayType = TypeProvider::bytesMemory();
|
||||||
|
|
||||||
@ -1339,10 +1339,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
}
|
}
|
||||||
case FunctionType::Kind::ArrayPop:
|
case FunctionType::Kind::ArrayPop:
|
||||||
{
|
{
|
||||||
solAssert(functionType->bound(), "");
|
solAssert(functionType->bound());
|
||||||
solAssert(functionType->parameterTypes().empty(), "");
|
solAssert(functionType->parameterTypes().empty());
|
||||||
ArrayType const* arrayType = dynamic_cast<ArrayType const*>(functionType->selfType());
|
ArrayType const* arrayType = dynamic_cast<ArrayType const*>(functionType->selfType());
|
||||||
solAssert(arrayType, "");
|
solAssert(arrayType);
|
||||||
define(_functionCall) <<
|
define(_functionCall) <<
|
||||||
m_utils.storageArrayPopFunction(*arrayType) <<
|
m_utils.storageArrayPopFunction(*arrayType) <<
|
||||||
"(" <<
|
"(" <<
|
||||||
@ -1353,7 +1353,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::ArrayPush:
|
case FunctionType::Kind::ArrayPush:
|
||||||
{
|
{
|
||||||
ArrayType const* arrayType = dynamic_cast<ArrayType const*>(functionType->selfType());
|
ArrayType const* arrayType = dynamic_cast<ArrayType const*>(functionType->selfType());
|
||||||
solAssert(arrayType, "");
|
solAssert(arrayType);
|
||||||
|
|
||||||
if (arguments.empty())
|
if (arguments.empty())
|
||||||
{
|
{
|
||||||
@ -1414,8 +1414,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
{FunctionType::Kind::AddMod, "addmod"},
|
{FunctionType::Kind::AddMod, "addmod"},
|
||||||
{FunctionType::Kind::MulMod, "mulmod"},
|
{FunctionType::Kind::MulMod, "mulmod"},
|
||||||
};
|
};
|
||||||
solAssert(functions.find(functionType->kind()) != functions.end(), "");
|
solAssert(functions.find(functionType->kind()) != functions.end());
|
||||||
solAssert(arguments.size() == 3 && parameterTypes.size() == 3, "");
|
solAssert(arguments.size() == 3 && parameterTypes.size() == 3);
|
||||||
|
|
||||||
IRVariable modulus(m_context.newYulVariable(), *(parameterTypes[2]));
|
IRVariable modulus(m_context.newYulVariable(), *(parameterTypes[2]));
|
||||||
define(modulus, *arguments[2]);
|
define(modulus, *arguments[2]);
|
||||||
@ -1440,7 +1440,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
{FunctionType::Kind::Selfdestruct, "selfdestruct"},
|
{FunctionType::Kind::Selfdestruct, "selfdestruct"},
|
||||||
{FunctionType::Kind::BlockHash, "blockhash"},
|
{FunctionType::Kind::BlockHash, "blockhash"},
|
||||||
};
|
};
|
||||||
solAssert(functions.find(functionType->kind()) != functions.end(), "");
|
solAssert(functions.find(functionType->kind()) != functions.end());
|
||||||
|
|
||||||
string args;
|
string args;
|
||||||
for (size_t i = 0; i < arguments.size(); ++i)
|
for (size_t i = 0; i < arguments.size(); ++i)
|
||||||
@ -1497,7 +1497,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
t("saltSet", functionType->saltSet());
|
t("saltSet", functionType->saltSet());
|
||||||
if (functionType->saltSet())
|
if (functionType->saltSet())
|
||||||
t("salt", IRVariable(_functionCall.expression()).part("salt").name());
|
t("salt", IRVariable(_functionCall.expression()).part("salt").name());
|
||||||
solAssert(IRVariable(_functionCall).stackSlots().size() == 1, "");
|
solAssert(IRVariable(_functionCall).stackSlots().size() == 1);
|
||||||
t("address", IRVariable(_functionCall).commaSeparatedList());
|
t("address", IRVariable(_functionCall).commaSeparatedList());
|
||||||
t("isTryCall", _functionCall.annotation().tryCall);
|
t("isTryCall", _functionCall.annotation().tryCall);
|
||||||
if (_functionCall.annotation().tryCall)
|
if (_functionCall.annotation().tryCall)
|
||||||
@ -1511,7 +1511,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::Send:
|
case FunctionType::Kind::Send:
|
||||||
case FunctionType::Kind::Transfer:
|
case FunctionType::Kind::Transfer:
|
||||||
{
|
{
|
||||||
solAssert(arguments.size() == 1 && parameterTypes.size() == 1, "");
|
solAssert(arguments.size() == 1 && parameterTypes.size() == 1);
|
||||||
string address{IRVariable(_functionCall.expression()).part("address").name()};
|
string address{IRVariable(_functionCall.expression()).part("address").name()};
|
||||||
string value{expressionAsType(*arguments[0], *(parameterTypes[0]))};
|
string value{expressionAsType(*arguments[0], *(parameterTypes[0]))};
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
@ -1540,10 +1540,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::RIPEMD160:
|
case FunctionType::Kind::RIPEMD160:
|
||||||
case FunctionType::Kind::SHA256:
|
case FunctionType::Kind::SHA256:
|
||||||
{
|
{
|
||||||
solAssert(!_functionCall.annotation().tryCall, "");
|
solAssert(!_functionCall.annotation().tryCall);
|
||||||
solAssert(!functionType->valueSet(), "");
|
solAssert(!functionType->valueSet());
|
||||||
solAssert(!functionType->gasSet(), "");
|
solAssert(!functionType->gasSet());
|
||||||
solAssert(!functionType->bound(), "");
|
solAssert(!functionType->bound());
|
||||||
|
|
||||||
static map<FunctionType::Kind, std::tuple<unsigned, size_t>> precompiles = {
|
static map<FunctionType::Kind, std::tuple<unsigned, size_t>> precompiles = {
|
||||||
{FunctionType::Kind::ECRecover, std::make_tuple(1, 0)},
|
{FunctionType::Kind::ECRecover, std::make_tuple(1, 0)},
|
||||||
@ -1618,7 +1618,7 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options)
|
|||||||
for (size_t i = 0; i < _options.names().size(); ++i)
|
for (size_t i = 0; i < _options.names().size(); ++i)
|
||||||
{
|
{
|
||||||
string const& name = *_options.names()[i];
|
string const& name = *_options.names()[i];
|
||||||
solAssert(name == "salt" || name == "gas" || name == "value", "");
|
solAssert(name == "salt" || name == "gas" || name == "value");
|
||||||
|
|
||||||
define(IRVariable(_options).part(name), *_options.options()[i]);
|
define(IRVariable(_options).part(name), *_options.options()[i]);
|
||||||
}
|
}
|
||||||
@ -1636,7 +1636,7 @@ bool IRGeneratorForStatements::visit(MemberAccess const& _memberAccess)
|
|||||||
innerExpression->expression().annotation().type->category() == Type::Category::Address
|
innerExpression->expression().annotation().type->category() == Type::Category::Address
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(innerExpression->annotation().type->category() == Type::Category::Array, "");
|
solAssert(innerExpression->annotation().type->category() == Type::Category::Array);
|
||||||
// Skip visiting <address>.code
|
// Skip visiting <address>.code
|
||||||
innerExpression->expression().accept(*this);
|
innerExpression->expression().accept(*this);
|
||||||
|
|
||||||
@ -1657,7 +1657,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
if (memberFunctionType && memberFunctionType->bound())
|
if (memberFunctionType && memberFunctionType->bound())
|
||||||
{
|
{
|
||||||
define(IRVariable(_memberAccess).part("self"), _memberAccess.expression());
|
define(IRVariable(_memberAccess).part("self"), _memberAccess.expression());
|
||||||
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
|
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static);
|
||||||
if (memberFunctionType->kind() == FunctionType::Kind::Internal)
|
if (memberFunctionType->kind() == FunctionType::Kind::Internal)
|
||||||
assignInternalFunctionIDIfNotCalledDirectly(
|
assignInternalFunctionIDIfNotCalledDirectly(
|
||||||
_memberAccess,
|
_memberAccess,
|
||||||
@ -1673,9 +1673,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto const& functionDefinition = dynamic_cast<FunctionDefinition const&>(memberFunctionType->declaration());
|
auto const& functionDefinition = dynamic_cast<FunctionDefinition const&>(memberFunctionType->declaration());
|
||||||
solAssert(memberFunctionType->kind() == FunctionType::Kind::DelegateCall, "");
|
solAssert(memberFunctionType->kind() == FunctionType::Kind::DelegateCall);
|
||||||
auto contract = dynamic_cast<ContractDefinition const*>(functionDefinition.scope());
|
auto contract = dynamic_cast<ContractDefinition const*>(functionDefinition.scope());
|
||||||
solAssert(contract && contract->isLibrary(), "");
|
solAssert(contract && contract->isLibrary());
|
||||||
define(IRVariable(_memberAccess).part("address")) << linkerSymbol(*contract) << "\n";
|
define(IRVariable(_memberAccess).part("address")) << linkerSymbol(*contract) << "\n";
|
||||||
define(IRVariable(_memberAccess).part("functionSelector")) << memberFunctionType->externalIdentifier() << "\n";
|
define(IRVariable(_memberAccess).part("functionSelector")) << memberFunctionType->externalIdentifier() << "\n";
|
||||||
}
|
}
|
||||||
@ -1688,7 +1688,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
|
ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
|
||||||
if (type.isSuper())
|
if (type.isSuper())
|
||||||
solAssert(false, "");
|
solAssert(false);
|
||||||
|
|
||||||
// ordinary contract type
|
// ordinary contract type
|
||||||
else if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
|
else if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
|
||||||
@ -1736,7 +1736,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
")\n";
|
")\n";
|
||||||
else if (set<string>{"send", "transfer"}.count(member))
|
else if (set<string>{"send", "transfer"}.count(member))
|
||||||
{
|
{
|
||||||
solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, "");
|
solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable);
|
||||||
define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression());
|
define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression());
|
||||||
}
|
}
|
||||||
else if (set<string>{"call", "callcode", "delegatecall", "staticcall"}.count(member))
|
else if (set<string>{"call", "callcode", "delegatecall", "staticcall"}.count(member))
|
||||||
@ -1764,7 +1764,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
functionType.kind() == FunctionType::Kind::Internal
|
functionType.kind() == FunctionType::Kind::Internal
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(functionType.hasDeclaration(), "");
|
solAssert(functionType.hasDeclaration());
|
||||||
solAssert(
|
solAssert(
|
||||||
functionType.kind() == FunctionType::Kind::Error ||
|
functionType.kind() == FunctionType::Kind::Error ||
|
||||||
functionType.declaration().isPartOfExternalInterface(),
|
functionType.declaration().isPartOfExternalInterface(),
|
||||||
@ -1832,7 +1832,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
|
Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
|
||||||
auto const& contractType = dynamic_cast<ContractType const&>(*arg);
|
auto const& contractType = dynamic_cast<ContractType const&>(*arg);
|
||||||
solAssert(!contractType.isSuper(), "");
|
solAssert(!contractType.isSuper());
|
||||||
ContractDefinition const& contract = contractType.contractDefinition();
|
ContractDefinition const& contract = contractType.contractDefinition();
|
||||||
m_context.subObjectsCreated().insert(&contract);
|
m_context.subObjectsCreated().insert(&contract);
|
||||||
appendCode() << Whiskers(R"(
|
appendCode() << Whiskers(R"(
|
||||||
@ -1856,7 +1856,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
|
Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
|
||||||
auto const& contractType = dynamic_cast<ContractType const&>(*arg);
|
auto const& contractType = dynamic_cast<ContractType const&>(*arg);
|
||||||
solAssert(!contractType.isSuper(), "");
|
solAssert(!contractType.isSuper());
|
||||||
ContractDefinition const& contract = contractType.contractDefinition();
|
ContractDefinition const& contract = contractType.contractDefinition();
|
||||||
define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n";
|
define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n";
|
||||||
}
|
}
|
||||||
@ -1983,7 +1983,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
}
|
}
|
||||||
else if (member == "pop" || member == "push")
|
else if (member == "pop" || member == "push")
|
||||||
{
|
{
|
||||||
solAssert(type.location() == DataLocation::Storage, "");
|
solAssert(type.location() == DataLocation::Storage);
|
||||||
define(IRVariable{_memberAccess}.part("slot"), IRVariable{_memberAccess.expression()}.part("slot"));
|
define(IRVariable{_memberAccess}.part("slot"), IRVariable{_memberAccess.expression()}.part("slot"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2019,8 +2019,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
*_memberAccess.annotation().referencedDeclaration
|
*_memberAccess.annotation().referencedDeclaration
|
||||||
).resolveVirtual(m_context.mostDerivedContract(), super);
|
).resolveVirtual(m_context.mostDerivedContract(), super);
|
||||||
|
|
||||||
solAssert(resolvedFunctionDef.functionType(true), "");
|
solAssert(resolvedFunctionDef.functionType(true));
|
||||||
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
|
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal);
|
||||||
assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, resolvedFunctionDef);
|
assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, resolvedFunctionDef);
|
||||||
}
|
}
|
||||||
else if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
else if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
||||||
@ -2078,19 +2078,19 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
// The old code generator had a generic "else" case here
|
// The old code generator had a generic "else" case here
|
||||||
// without any specific code being generated,
|
// without any specific code being generated,
|
||||||
// but it would still be better to have an exhaustive list.
|
// but it would still be better to have an exhaustive list.
|
||||||
solAssert(false, "");
|
solAssert(false);
|
||||||
}
|
}
|
||||||
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
|
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
|
||||||
define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n";
|
define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n";
|
||||||
else if (dynamic_cast<UserDefinedValueType const*>(&actualType))
|
else if (dynamic_cast<UserDefinedValueType const*>(&actualType))
|
||||||
solAssert(member == "wrap" || member == "unwrap", "");
|
solAssert(member == "wrap" || member == "unwrap");
|
||||||
else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType))
|
else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType))
|
||||||
solAssert(arrayType->isByteArray() && member == "concat", "");
|
solAssert(arrayType->isByteArray() && member == "concat");
|
||||||
else
|
else
|
||||||
// The old code generator had a generic "else" case here
|
// The old code generator had a generic "else" case here
|
||||||
// without any specific code being generated,
|
// without any specific code being generated,
|
||||||
// but it would still be better to have an exhaustive list.
|
// but it would still be better to have an exhaustive list.
|
||||||
solAssert(false, "");
|
solAssert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Module:
|
case Type::Category::Module:
|
||||||
@ -2106,17 +2106,17 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
);
|
);
|
||||||
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
||||||
{
|
{
|
||||||
solAssert(variable->isConstant(), "");
|
solAssert(variable->isConstant());
|
||||||
handleVariableReference(*variable, static_cast<Expression const&>(_memberAccess));
|
handleVariableReference(*variable, static_cast<Expression const&>(_memberAccess));
|
||||||
}
|
}
|
||||||
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
|
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
|
||||||
{
|
{
|
||||||
auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
|
auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
|
||||||
solAssert(function && function->isFree(), "");
|
solAssert(function && function->isFree());
|
||||||
solAssert(function->functionType(true), "");
|
solAssert(function->functionType(true));
|
||||||
solAssert(function->functionType(true)->kind() == FunctionType::Kind::Internal, "");
|
solAssert(function->functionType(true)->kind() == FunctionType::Kind::Internal);
|
||||||
solAssert(funType->kind() == FunctionType::Kind::Internal, "");
|
solAssert(funType->kind() == FunctionType::Kind::Internal);
|
||||||
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
|
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static);
|
||||||
|
|
||||||
assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, *function);
|
assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, *function);
|
||||||
}
|
}
|
||||||
@ -2140,7 +2140,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
|||||||
|
|
||||||
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
||||||
|
|
||||||
solAssert(holds_alternative<yul::Block>(modified), "");
|
solAssert(holds_alternative<yul::Block>(modified));
|
||||||
|
|
||||||
// Do not provide dialect so that we get the full type information.
|
// Do not provide dialect so that we get the full type information.
|
||||||
appendCode() << yul::AsmPrinter()(std::get<yul::Block>(modified)) << "\n";
|
appendCode() << yul::AsmPrinter()(std::get<yul::Block>(modified)) << "\n";
|
||||||
@ -2183,7 +2183,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
|||||||
dynamic_cast<ArraySliceType const&>(baseType).arrayType();
|
dynamic_cast<ArraySliceType const&>(baseType).arrayType();
|
||||||
|
|
||||||
if (baseType.category() == Type::Category::ArraySlice)
|
if (baseType.category() == Type::Category::ArraySlice)
|
||||||
solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized(), "");
|
solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized());
|
||||||
|
|
||||||
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
||||||
|
|
||||||
@ -2276,8 +2276,8 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
|||||||
}
|
}
|
||||||
else if (baseType.category() == Type::Category::TypeType)
|
else if (baseType.category() == Type::Category::TypeType)
|
||||||
{
|
{
|
||||||
solAssert(baseType.sizeOnStack() == 0, "");
|
solAssert(baseType.sizeOnStack() == 0);
|
||||||
solAssert(_indexAccess.annotation().type->sizeOnStack() == 0, "");
|
solAssert(_indexAccess.annotation().type->sizeOnStack() == 0);
|
||||||
// no-op - this seems to be a lone array type (`structType[];`)
|
// no-op - this seems to be a lone array type (`structType[];`)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2302,7 +2302,7 @@ void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAcces
|
|||||||
{
|
{
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
{
|
{
|
||||||
solAssert(baseType.isDynamicallySized(), "");
|
solAssert(baseType.isDynamicallySized());
|
||||||
IRVariable sliceStart{m_context.newYulVariable(), *TypeProvider::uint256()};
|
IRVariable sliceStart{m_context.newYulVariable(), *TypeProvider::uint256()};
|
||||||
if (_indexRangeAccess.startExpression())
|
if (_indexRangeAccess.startExpression())
|
||||||
define(sliceStart, IRVariable{*_indexRangeAccess.startExpression()});
|
define(sliceStart, IRVariable{*_indexRangeAccess.startExpression()});
|
||||||
@ -2340,18 +2340,18 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
|||||||
switch (magicVar->type()->category())
|
switch (magicVar->type()->category())
|
||||||
{
|
{
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
solAssert(_identifier.name() == "this", "");
|
solAssert(_identifier.name() == "this");
|
||||||
define(_identifier) << "address()\n";
|
define(_identifier) << "address()\n";
|
||||||
break;
|
break;
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
solAssert(_identifier.name() == "now", "");
|
solAssert(_identifier.name() == "now");
|
||||||
define(_identifier) << "timestamp()\n";
|
define(_identifier) << "timestamp()\n";
|
||||||
break;
|
break;
|
||||||
case Type::Category::TypeType:
|
case Type::Category::TypeType:
|
||||||
{
|
{
|
||||||
auto typeType = dynamic_cast<TypeType const*>(magicVar->type());
|
auto typeType = dynamic_cast<TypeType const*>(magicVar->type());
|
||||||
if (auto contractType = dynamic_cast<ContractType const*>(typeType->actualType()))
|
if (auto contractType = dynamic_cast<ContractType const*>(typeType->actualType()))
|
||||||
solAssert(!contractType->isSuper() || _identifier.name() == "super", "");
|
solAssert(!contractType->isSuper() || _identifier.name() == "super");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -2361,11 +2361,11 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
|||||||
}
|
}
|
||||||
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, "");
|
solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual);
|
||||||
FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract());
|
FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||||
|
|
||||||
solAssert(resolvedFunctionDef.functionType(true), "");
|
solAssert(resolvedFunctionDef.functionType(true));
|
||||||
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
|
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal);
|
||||||
assignInternalFunctionIDIfNotCalledDirectly(_identifier, resolvedFunctionDef);
|
assignInternalFunctionIDIfNotCalledDirectly(_identifier, resolvedFunctionDef);
|
||||||
}
|
}
|
||||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
@ -2460,9 +2460,9 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression()));
|
FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression()));
|
||||||
solAssert(!funType.takesArbitraryParameters(), "");
|
solAssert(!funType.takesArbitraryParameters());
|
||||||
solAssert(_arguments.size() == funType.parameterTypes().size(), "");
|
solAssert(_arguments.size() == funType.parameterTypes().size());
|
||||||
solAssert(!funType.isBareCall(), "");
|
solAssert(!funType.isBareCall());
|
||||||
FunctionType::Kind const funKind = funType.kind();
|
FunctionType::Kind const funKind = funType.kind();
|
||||||
|
|
||||||
solAssert(
|
solAssert(
|
||||||
@ -2566,7 +2566,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
|
|
||||||
string const retVars = IRVariable(_functionCall).commaSeparatedList();
|
string const retVars = IRVariable(_functionCall).commaSeparatedList();
|
||||||
templ("retVars", retVars);
|
templ("retVars", retVars);
|
||||||
solAssert(retVars.empty() == returnInfo.returnTypes.empty(), "");
|
solAssert(retVars.empty() == returnInfo.returnTypes.empty());
|
||||||
|
|
||||||
templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true));
|
templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true));
|
||||||
templ("dynamicReturnSize", returnInfo.dynamicReturnSize);
|
templ("dynamicReturnSize", returnInfo.dynamicReturnSize);
|
||||||
@ -2575,7 +2575,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
|
|||||||
|
|
||||||
bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall;
|
bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall;
|
||||||
|
|
||||||
solAssert(funType.padArguments(), "");
|
solAssert(funType.padArguments());
|
||||||
templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes, encodeForLibraryCall));
|
templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes, encodeForLibraryCall));
|
||||||
templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
|
templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
|
||||||
|
|
||||||
@ -2628,7 +2628,7 @@ void IRGeneratorForStatements::appendBareCall(
|
|||||||
);
|
);
|
||||||
FunctionType::Kind const funKind = funType.kind();
|
FunctionType::Kind const funKind = funType.kind();
|
||||||
|
|
||||||
solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), "");
|
solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall());
|
||||||
solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed.");
|
solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed.");
|
||||||
solAssert(
|
solAssert(
|
||||||
funKind == FunctionType::Kind::BareCall ||
|
funKind == FunctionType::Kind::BareCall ||
|
||||||
@ -2636,7 +2636,7 @@ void IRGeneratorForStatements::appendBareCall(
|
|||||||
funKind == FunctionType::Kind::BareStaticCall, ""
|
funKind == FunctionType::Kind::BareStaticCall, ""
|
||||||
);
|
);
|
||||||
|
|
||||||
solAssert(!_functionCall.annotation().tryCall, "");
|
solAssert(!_functionCall.annotation().tryCall);
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
<?needsEncoding>
|
<?needsEncoding>
|
||||||
let <pos> := <allocateUnbounded>()
|
let <pos> := <allocateUnbounded>()
|
||||||
@ -2848,7 +2848,7 @@ string IRGeneratorForStatements::binaryOperation(
|
|||||||
"Not yet implemented - FixedPointType."
|
"Not yet implemented - FixedPointType."
|
||||||
);
|
);
|
||||||
IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
|
IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
|
||||||
solAssert(type, "");
|
solAssert(type);
|
||||||
bool checked = m_context.arithmetic() == Arithmetic::Checked;
|
bool checked = m_context.arithmetic() == Arithmetic::Checked;
|
||||||
switch (_operator)
|
switch (_operator)
|
||||||
{
|
{
|
||||||
@ -2888,9 +2888,9 @@ std::string IRGeneratorForStatements::shiftOperation(
|
|||||||
"Not yet implemented - FixedPointType."
|
"Not yet implemented - FixedPointType."
|
||||||
);
|
);
|
||||||
IntegerType const* amountType = dynamic_cast<IntegerType const*>(&_amountToShift.type());
|
IntegerType const* amountType = dynamic_cast<IntegerType const*>(&_amountToShift.type());
|
||||||
solAssert(amountType, "");
|
solAssert(amountType);
|
||||||
|
|
||||||
solAssert(_operator == Token::SHL || _operator == Token::SAR, "");
|
solAssert(_operator == Token::SHL || _operator == Token::SAR);
|
||||||
|
|
||||||
return
|
return
|
||||||
Whiskers(R"(
|
Whiskers(R"(
|
||||||
@ -2909,7 +2909,7 @@ std::string IRGeneratorForStatements::shiftOperation(
|
|||||||
void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
|
void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
|
||||||
{
|
{
|
||||||
langutil::Token const op = _binOp.getOperator();
|
langutil::Token const op = _binOp.getOperator();
|
||||||
solAssert(op == Token::Or || op == Token::And, "");
|
solAssert(op == Token::Or || op == Token::And);
|
||||||
|
|
||||||
_binOp.leftExpression().accept(*this);
|
_binOp.leftExpression().accept(*this);
|
||||||
setLocation(_binOp);
|
setLocation(_binOp);
|
||||||
@ -2956,7 +2956,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
|||||||
|
|
||||||
if (_memory.byteArrayElement)
|
if (_memory.byteArrayElement)
|
||||||
{
|
{
|
||||||
solAssert(_lvalue.type == *TypeProvider::byte(), "");
|
solAssert(_lvalue.type == *TypeProvider::byte());
|
||||||
appendCode() << "mstore8(" + _memory.address + ", byte(0, " + prepared.commaSeparatedList() + "))\n";
|
appendCode() << "mstore8(" + _memory.address + ", byte(0, " + prepared.commaSeparatedList() + "))\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2980,9 +2980,9 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(_lvalue.type.sizeOnStack() == 1, "");
|
solAssert(_lvalue.type.sizeOnStack() == 1);
|
||||||
auto const* valueReferenceType = dynamic_cast<ReferenceType const*>(&_value.type());
|
auto const* valueReferenceType = dynamic_cast<ReferenceType const*>(&_value.type());
|
||||||
solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory), "");
|
solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory));
|
||||||
appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n";
|
appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2991,7 +2991,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
|
|||||||
{
|
{
|
||||||
solUnimplementedAssert(_lvalue.type.isValueType());
|
solUnimplementedAssert(_lvalue.type.isValueType());
|
||||||
solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1);
|
solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1);
|
||||||
solAssert(_lvalue.type == *_immutable.variable->type(), "");
|
solAssert(_lvalue.type == *_immutable.variable->type());
|
||||||
size_t memOffset = m_context.immutableMemoryOffset(*_immutable.variable);
|
size_t memOffset = m_context.immutableMemoryOffset(*_immutable.variable);
|
||||||
|
|
||||||
IRVariable prepared(m_context.newYulVariable(), _lvalue.type);
|
IRVariable prepared(m_context.newYulVariable(), _lvalue.type);
|
||||||
@ -3051,7 +3051,7 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue)
|
|||||||
[&](IRLValue::Immutable const& _immutable) {
|
[&](IRLValue::Immutable const& _immutable) {
|
||||||
solUnimplementedAssert(_lvalue.type.isValueType());
|
solUnimplementedAssert(_lvalue.type.isValueType());
|
||||||
solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1);
|
solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1);
|
||||||
solAssert(_lvalue.type == *_immutable.variable->type(), "");
|
solAssert(_lvalue.type == *_immutable.variable->type());
|
||||||
if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation)
|
if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation)
|
||||||
{
|
{
|
||||||
string readFunction = m_utils.readFromMemory(*_immutable.variable->type());
|
string readFunction = m_utils.readFromMemory(*_immutable.variable->type());
|
||||||
@ -3073,13 +3073,13 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue)
|
|||||||
|
|
||||||
void IRGeneratorForStatements::setLValue(Expression const& _expression, IRLValue _lvalue)
|
void IRGeneratorForStatements::setLValue(Expression const& _expression, IRLValue _lvalue)
|
||||||
{
|
{
|
||||||
solAssert(!m_currentLValue, "");
|
solAssert(!m_currentLValue);
|
||||||
|
|
||||||
if (_expression.annotation().willBeWrittenTo)
|
if (_expression.annotation().willBeWrittenTo)
|
||||||
{
|
{
|
||||||
m_currentLValue.emplace(std::move(_lvalue));
|
m_currentLValue.emplace(std::move(_lvalue));
|
||||||
if (_lvalue.type.dataStoredIn(DataLocation::CallData))
|
if (_lvalue.type.dataStoredIn(DataLocation::CallData))
|
||||||
solAssert(holds_alternative<IRLValue::Stack>(_lvalue.kind), "");
|
solAssert(holds_alternative<IRLValue::Stack>(_lvalue.kind));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// Only define the expression, if it will not be written to.
|
// Only define the expression, if it will not be written to.
|
||||||
@ -3153,7 +3153,7 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement)
|
|||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (ASTPointer<VariableDeclaration> const& varDecl: successClause.parameters()->parameters())
|
for (ASTPointer<VariableDeclaration> const& varDecl: successClause.parameters()->parameters())
|
||||||
{
|
{
|
||||||
solAssert(varDecl, "");
|
solAssert(varDecl);
|
||||||
define(m_context.addLocalVariable(*varDecl),
|
define(m_context.addLocalVariable(*varDecl),
|
||||||
successClause.parameters()->parameters().size() == 1 ?
|
successClause.parameters()->parameters().size() == 1 ?
|
||||||
IRVariable(externalCall) :
|
IRVariable(externalCall) :
|
||||||
@ -3194,7 +3194,7 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
|
|||||||
appendCode() << runFallback << " := 0\n";
|
appendCode() << runFallback << " := 0\n";
|
||||||
if (errorClause->parameters())
|
if (errorClause->parameters())
|
||||||
{
|
{
|
||||||
solAssert(errorClause->parameters()->parameters().size() == 1, "");
|
solAssert(errorClause->parameters()->parameters().size() == 1);
|
||||||
IRVariable const& var = m_context.addLocalVariable(*errorClause->parameters()->parameters().front());
|
IRVariable const& var = m_context.addLocalVariable(*errorClause->parameters()->parameters().front());
|
||||||
define(var) << dataVariable << "\n";
|
define(var) << dataVariable << "\n";
|
||||||
}
|
}
|
||||||
@ -3215,7 +3215,7 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
|
|||||||
appendCode() << runFallback << " := 0\n";
|
appendCode() << runFallback << " := 0\n";
|
||||||
if (panicClause->parameters())
|
if (panicClause->parameters())
|
||||||
{
|
{
|
||||||
solAssert(panicClause->parameters()->parameters().size() == 1, "");
|
solAssert(panicClause->parameters()->parameters().size() == 1);
|
||||||
IRVariable const& var = m_context.addLocalVariable(*panicClause->parameters()->parameters().front());
|
IRVariable const& var = m_context.addLocalVariable(*panicClause->parameters()->parameters().front());
|
||||||
define(var) << code << "\n";
|
define(var) << code << "\n";
|
||||||
}
|
}
|
||||||
@ -3241,7 +3241,7 @@ void IRGeneratorForStatements::handleCatchFallback(TryCatchClause const& _fallba
|
|||||||
setLocation(_fallback);
|
setLocation(_fallback);
|
||||||
if (_fallback.parameters())
|
if (_fallback.parameters())
|
||||||
{
|
{
|
||||||
solAssert(m_context.evmVersion().supportsReturndata(), "");
|
solAssert(m_context.evmVersion().supportsReturndata());
|
||||||
solAssert(
|
solAssert(
|
||||||
_fallback.parameters()->parameters().size() == 1 &&
|
_fallback.parameters()->parameters().size() == 1 &&
|
||||||
_fallback.parameters()->parameters().front() &&
|
_fallback.parameters()->parameters().front() &&
|
||||||
@ -3277,7 +3277,7 @@ void IRGeneratorForStatements::revertWithError(
|
|||||||
for (ASTPointer<Expression const> const& arg: _errorArguments)
|
for (ASTPointer<Expression const> const& arg: _errorArguments)
|
||||||
{
|
{
|
||||||
errorArgumentVars += IRVariable(*arg).stackSlots();
|
errorArgumentVars += IRVariable(*arg).stackSlots();
|
||||||
solAssert(arg->annotation().type, "");
|
solAssert(arg->annotation().type);
|
||||||
errorArgumentTypes.push_back(arg->annotation().type);
|
errorArgumentTypes.push_back(arg->annotation().type);
|
||||||
}
|
}
|
||||||
templ("argumentVars", joinHumanReadablePrefixed(errorArgumentVars));
|
templ("argumentVars", joinHumanReadablePrefixed(errorArgumentVars));
|
||||||
@ -3295,6 +3295,6 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause)
|
|||||||
|
|
||||||
string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const
|
string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const
|
||||||
{
|
{
|
||||||
solAssert(_library.isLibrary(), "");
|
solAssert(_library.isLibrary());
|
||||||
return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")";
|
return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")";
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
// Triggered ICE before
|
||||||
|
contract C {
|
||||||
|
function f(string calldata data) external pure returns(string memory) {
|
||||||
|
bytes calldata test = bytes(data[:3]);
|
||||||
|
return string(test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(string): 0x20, 3, "123" -> 0x20, 3, "123"
|
Loading…
Reference in New Issue
Block a user