Merge pull request #261 from chriseth/dataloc

Bugfix for explicit memory types in libraries.
This commit is contained in:
chriseth 2015-12-01 12:15:17 +01:00
commit e853eb22fa

View File

@ -128,19 +128,21 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
{ {
type = _variable.typeName()->annotation().type; type = _variable.typeName()->annotation().type;
using Location = VariableDeclaration::Location; using Location = VariableDeclaration::Location;
Location loc = _variable.referenceLocation(); Location varLoc = _variable.referenceLocation();
DataLocation typeLoc = DataLocation::Memory;
// References are forced to calldata for external function parameters (not return) // References are forced to calldata for external function parameters (not return)
// and memory for parameters (also return) of publicly visible functions. // and memory for parameters (also return) of publicly visible functions.
// They default to memory for function parameters and storage for local variables. // They default to memory for function parameters and storage for local variables.
// As an exception, "storage" is allowed for library functions. // As an exception, "storage" is allowed for library functions.
if (auto ref = dynamic_cast<ReferenceType const*>(type.get())) if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
{ {
bool isPointer = true;
if (_variable.isExternalCallableParameter()) if (_variable.isExternalCallableParameter())
{ {
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope()); auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
if (contract.isLibrary()) if (contract.isLibrary())
{ {
if (loc == Location::Memory) if (varLoc == Location::Memory)
fatalTypeError(_variable.location(), fatalTypeError(_variable.location(),
"Location has to be calldata or storage for external " "Location has to be calldata or storage for external "
"library functions (remove the \"memory\" keyword)." "library functions (remove the \"memory\" keyword)."
@ -149,50 +151,52 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
else else
{ {
// force location of external function parameters (not return) to calldata // force location of external function parameters (not return) to calldata
if (loc != Location::Default) if (varLoc != Location::Default)
fatalTypeError(_variable.location(), fatalTypeError(_variable.location(),
"Location has to be calldata for external functions " "Location has to be calldata for external functions "
"(remove the \"memory\" or \"storage\" keyword)." "(remove the \"memory\" or \"storage\" keyword)."
); );
} }
if (loc == Location::Default) if (varLoc == Location::Default)
type = ref->copyForLocation(DataLocation::CallData, true); typeLoc = DataLocation::CallData;
else
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
} }
else if (_variable.isCallableParameter() && _variable.scope()->isPublic()) else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
{ {
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope()); auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
// force locations of public or external function (return) parameters to memory // force locations of public or external function (return) parameters to memory
if (loc == Location::Storage && !contract.isLibrary()) if (varLoc == Location::Storage && !contract.isLibrary())
fatalTypeError(_variable.location(), fatalTypeError(_variable.location(),
"Location has to be memory for publicly visible functions " "Location has to be memory for publicly visible functions "
"(remove the \"storage\" keyword)." "(remove the \"storage\" keyword)."
); );
if (loc == Location::Default || !contract.isLibrary()) if (varLoc == Location::Default || !contract.isLibrary())
type = ref->copyForLocation(DataLocation::Memory, true); typeLoc = DataLocation::Memory;
else
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
} }
else else
{ {
if (_variable.isConstant()) if (_variable.isConstant())
{ {
if (loc != Location::Default && loc != Location::Memory) if (varLoc != Location::Default && varLoc != Location::Memory)
fatalTypeError( fatalTypeError(
_variable.location(), _variable.location(),
"Storage location has to be \"memory\" (or unspecified) for constants." "Storage location has to be \"memory\" (or unspecified) for constants."
); );
loc = Location::Memory; typeLoc = DataLocation::Memory;
} }
if (loc == Location::Default) else if (varLoc == Location::Default)
loc = _variable.isCallableParameter() ? Location::Memory : Location::Storage; typeLoc = _variable.isCallableParameter() ? DataLocation::Memory : DataLocation::Storage;
bool isPointer = !_variable.isStateVariable(); else
type = ref->copyForLocation( typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
loc == Location::Memory ? isPointer = !_variable.isStateVariable();
DataLocation::Memory :
DataLocation::Storage,
isPointer
);
} }
type = ref->copyForLocation(typeLoc, isPointer);
} }
else if (loc != Location::Default && !ref) else if (varLoc != Location::Default && !ref)
fatalTypeError(_variable.location(), "Storage location can only be given for array or struct types."); fatalTypeError(_variable.location(), "Storage location can only be given for array or struct types.");
if (!type) if (!type)