aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/Compiler.cpp11
-rw-r--r--libsolidity/Compiler.h2
-rw-r--r--libsolidity/CompilerUtils.cpp5
-rw-r--r--libsolidity/CompilerUtils.h5
-rw-r--r--libsolidity/ReferencesResolver.cpp54
-rw-r--r--libsolidity/Types.cpp8
-rw-r--r--libsolidity/Types.h3
7 files changed, 50 insertions, 38 deletions
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index 21eab230..1ef63bbf 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -252,7 +252,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
eth::AssemblyItem returnTag = m_context.pushNewTag();
fallback->accept(*this);
m_context << returnTag;
- appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes());
+ appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary());
}
else
m_context << eth::Instruction::STOP; // function not found
@@ -268,7 +268,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
appendCalldataUnpacker(functionType->parameterTypes());
m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration()));
m_context << returnTag;
- appendReturnValuePacker(functionType->returnParameterTypes());
+ appendReturnValuePacker(functionType->returnParameterTypes(), _contract.isLibrary());
}
}
@@ -283,7 +283,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
for (TypePointer const& parameterType: _typeParameters)
{
// stack: v1 v2 ... v(k-1) base_offset current_offset
- TypePointer type = parameterType->encodingType();
+ TypePointer type = parameterType->decodingType();
if (type->category() == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(*type);
@@ -340,7 +340,6 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack());
m_context << eth::Instruction::SWAP1;
}
- break;
}
else
{
@@ -354,7 +353,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
m_context << eth::Instruction::POP << eth::Instruction::POP;
}
-void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
+void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary)
{
CompilerUtils utils(m_context);
if (_typeParameters.empty())
@@ -364,7 +363,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
utils.fetchFreeMemoryPointer();
//@todo optimization: if we return a single memory array, there should be enough space before
// its data to add the needed parts and we avoid a memory copy.
- utils.encodeToMemory(_typeParameters, _typeParameters);
+ utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary);
utils.toSizeAfterFreeMemoryPointer();
m_context << eth::Instruction::RETURN;
}
diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h
index c3bb838a..3cf1004a 100644
--- a/libsolidity/Compiler.h
+++ b/libsolidity/Compiler.h
@@ -87,7 +87,7 @@ private:
/// From memory if @a _fromMemory is true, otherwise from call data.
/// Expects source offset on the stack, which is removed.
void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false);
- void appendReturnValuePacker(TypePointers const& _typeParameters);
+ void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary);
void registerStateVariables(ContractDefinition const& _contract);
void initializeStateVariables(ContractDefinition const& _contract);
diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp
index 31000f0b..583d267a 100644
--- a/libsolidity/CompilerUtils.cpp
+++ b/libsolidity/CompilerUtils.cpp
@@ -153,14 +153,15 @@ void CompilerUtils::encodeToMemory(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _padToWordBoundaries,
- bool _copyDynamicDataInPlace
+ bool _copyDynamicDataInPlace,
+ bool _encodeAsLibraryTypes
)
{
// stack: <v1> <v2> ... <vn> <mem>
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
solAssert(targetTypes.size() == _givenTypes.size(), "");
for (TypePointer& t: targetTypes)
- t = t->mobileType()->encodingType();
+ t = t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType();
// Stack during operation:
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h
index 568a6307..f335eed5 100644
--- a/libsolidity/CompilerUtils.h
+++ b/libsolidity/CompilerUtils.h
@@ -91,13 +91,16 @@ public:
/// @param _padToWordBoundaries if false, all values are concatenated without padding.
/// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length)
/// together with fixed-length data.
+ /// @param _encodeAsLibraryTypes if true, encodes for a library function, e.g. does not
+ /// convert storage pointer types to memory types.
/// @note the locations of target reference types are ignored, because it will always be
/// memory.
void encodeToMemory(
TypePointers const& _givenTypes = {},
TypePointers const& _targetTypes = {},
bool _padToWordBoundaries = true,
- bool _copyDynamicDataInPlace = false
+ bool _copyDynamicDataInPlace = false,
+ bool _encodeAsLibraryTypes = false
);
/// Uses a CALL to the identity contract to perform a memory-to-memory copy.
diff --git a/libsolidity/ReferencesResolver.cpp b/libsolidity/ReferencesResolver.cpp
index cb34c47e..f60ca1af 100644
--- a/libsolidity/ReferencesResolver.cpp
+++ b/libsolidity/ReferencesResolver.cpp
@@ -109,42 +109,40 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
// As an exception, "storage" is allowed for library functions.
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
{
- if (_variable.isCallableParameter())
+ if (_variable.isExternalCallableParameter())
{
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
- if (_variable.isExternalCallableParameter())
+ if (contract.isLibrary())
{
- if (contract.isLibrary())
- {
- if (loc == Location::Memory)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Location has to be calldata or storage for external "
- "library functions (remove the \"memory\" keyword)."
- ));
- }
- else
- {
- // force location of external function parameters (not return) to calldata
- if (loc != Location::Default)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Location has to be calldata for external functions "
- "(remove the \"memory\" or \"storage\" keyword)."
- ));
- }
- if (loc == Location::Default)
- type = ref->copyForLocation(DataLocation::CallData, true);
+ if (loc == Location::Memory)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be calldata or storage for external "
+ "library functions (remove the \"memory\" keyword)."
+ ));
}
- else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
+ else
{
- // force locations of public or external function (return) parameters to memory
- if (loc == Location::Storage && !contract.isLibrary())
+ // force location of external function parameters (not return) to calldata
+ if (loc != Location::Default)
BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Location has to be memory for publicly visible functions "
- "(remove the \"storage\" keyword)."
+ "Location has to be calldata for external functions "
+ "(remove the \"memory\" or \"storage\" keyword)."
));
- if (loc == Location::Default)
- type = ref->copyForLocation(DataLocation::Memory, true);
}
+ if (loc == Location::Default)
+ type = ref->copyForLocation(DataLocation::CallData, true);
+ }
+ else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
+ {
+ auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
+ // force locations of public or external function (return) parameters to memory
+ if (loc == Location::Storage && !contract.isLibrary())
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be memory for publicly visible functions "
+ "(remove the \"storage\" keyword)."
+ ));
+ if (loc == Location::Default || !contract.isLibrary())
+ type = ref->copyForLocation(DataLocation::Memory, true);
}
else
{
diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp
index f7e67696..faac2447 100644
--- a/libsolidity/Types.cpp
+++ b/libsolidity/Types.cpp
@@ -847,6 +847,14 @@ TypePointer ArrayType::encodingType() const
return this->copyForLocation(DataLocation::Memory, true);
}
+TypePointer ArrayType::decodingType() const
+{
+ if (location() == DataLocation::Storage)
+ return make_shared<IntegerType>(256);
+ else
+ return shared_from_this();
+}
+
TypePointer ArrayType::interfaceType(bool _inLibrary) const
{
if (_inLibrary && location() == DataLocation::Storage)
diff --git a/libsolidity/Types.h b/libsolidity/Types.h
index 972876e9..09654bfe 100644
--- a/libsolidity/Types.h
+++ b/libsolidity/Types.h
@@ -230,6 +230,8 @@ public:
/// This for example returns address for contract types.
/// If there is no such type, returns an empty shared pointer.
virtual TypePointer encodingType() const { return TypePointer(); }
+ /// @returns a (simpler) type that is used when decoding this type in calldata.
+ virtual TypePointer decodingType() const { return encodingType(); }
/// @returns a type that will be used outside of Solidity for e.g. function signatures.
/// This for example returns address for contract types.
/// If there is no such type, returns an empty shared pointer.
@@ -504,6 +506,7 @@ public:
return isString() ? EmptyMemberList : s_arrayTypeMemberList;
}
virtual TypePointer encodingType() const override;
+ virtual TypePointer decodingType() const override;
virtual TypePointer interfaceType(bool _inLibrary) const override;
/// @returns true if this is a byte array or a string