bool Compiler::visit(VariableDeclaration const& _variableDeclaration) { solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration."); CompilerContext::LocationSetter locationSetter(m_context, _variableDeclaration); m_context.startFunction(_variableDeclaration); m_breakTags.clear(); m_continueTags.clear(); ExpressionCompiler(m_context, m_optimize).appendStateVariableAccessor(_variableDeclaration); return false; }
void ReferencesResolver::endVisit(VariableDeclaration const& _variable) { if (_variable.annotation().type) return; TypePointer type; if (_variable.typeName()) { type = _variable.typeName()->annotation().type; using Location = VariableDeclaration::Location; Location varLoc = _variable.referenceLocation(); DataLocation typeLoc = DataLocation::Memory; // References are forced to calldata for external function parameters (not return) // and memory for parameters (also return) of publicly visible functions. // They default to memory for function parameters and storage for local variables. // As an exception, "storage" is allowed for library functions. if (auto ref = dynamic_cast<ReferenceType const*>(type.get())) { bool isPointer = true; if (_variable.isExternalCallableParameter()) { auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope()); if (contract.isLibrary()) { if (varLoc == Location::Memory) fatalTypeError(_variable.location(), "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 (varLoc != Location::Default) fatalTypeError(_variable.location(), "Location has to be calldata for external functions " "(remove the \"memory\" or \"storage\" keyword)." ); } if (varLoc == Location::Default) typeLoc = DataLocation::CallData; else typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; } 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 (varLoc == Location::Storage && !contract.isLibrary()) fatalTypeError(_variable.location(), "Location has to be memory for publicly visible functions " "(remove the \"storage\" keyword)." ); if (varLoc == Location::Default || !contract.isLibrary()) typeLoc = DataLocation::Memory; else typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; } else { if (_variable.isConstant()) { if (varLoc != Location::Default && varLoc != Location::Memory) fatalTypeError( _variable.location(), "Storage location has to be \"memory\" (or unspecified) for constants." ); typeLoc = DataLocation::Memory; } else if (varLoc == Location::Default) typeLoc = _variable.isCallableParameter() ? DataLocation::Memory : DataLocation::Storage; else typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; isPointer = !_variable.isStateVariable(); } type = ref->copyForLocation(typeLoc, isPointer); } else if (varLoc != Location::Default && !ref) fatalTypeError(_variable.location(), "Storage location can only be given for array or struct types."); if (!type) fatalTypeError(_variable.location(), "Invalid type name."); } else if (!_variable.canHaveAutoType()) fatalTypeError(_variable.location(), "Explicit type needed."); // otherwise we have a "var"-declaration whose type is resolved by the first assignment _variable.annotation().type = type; }