mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow using calldata keyword to specify data location
This commit is contained in:
@@ -327,7 +327,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
else
|
||||
{
|
||||
// force location of external function parameters (not return) to calldata
|
||||
if (varLoc != Location::Default)
|
||||
if (varLoc != Location::CallData && varLoc != Location::Default)
|
||||
fatalTypeError(_variable.location(),
|
||||
"Location has to be calldata for external functions "
|
||||
"(remove the \"memory\" or \"storage\" keyword)."
|
||||
@@ -344,15 +344,22 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
|
||||
);
|
||||
// force locations of public or external function (return) parameters to memory
|
||||
if (varLoc == Location::Storage && !contract.isLibrary())
|
||||
if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary())
|
||||
fatalTypeError(_variable.location(),
|
||||
"Location has to be memory for publicly visible functions "
|
||||
"(remove the \"storage\" keyword)."
|
||||
"(remove the \"storage\" or \"calldata\" keyword)."
|
||||
);
|
||||
if (varLoc == Location::Default || !contract.isLibrary())
|
||||
typeLoc = DataLocation::Memory;
|
||||
else
|
||||
{
|
||||
if (varLoc == Location::CallData)
|
||||
fatalTypeError(_variable.location(),
|
||||
"Location cannot be calldata for non-external functions "
|
||||
"(remove the \"calldata\" keyword)."
|
||||
);
|
||||
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -361,7 +368,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
if (varLoc != Location::Default && varLoc != Location::Memory)
|
||||
fatalTypeError(
|
||||
_variable.location(),
|
||||
"Storage location has to be \"memory\" (or unspecified) for constants."
|
||||
"Data location has to be \"memory\" (or unspecified) for constants."
|
||||
);
|
||||
typeLoc = DataLocation::Memory;
|
||||
}
|
||||
@@ -377,7 +384,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
if (_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
|
||||
typeError(
|
||||
_variable.location(),
|
||||
"Storage location must be specified as either \"memory\" or \"storage\"."
|
||||
"Data location must be specified as either \"memory\" or \"storage\"."
|
||||
);
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
@@ -389,14 +396,31 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
}
|
||||
}
|
||||
else
|
||||
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
|
||||
{
|
||||
switch (varLoc)
|
||||
{
|
||||
case Location::Memory:
|
||||
typeLoc = DataLocation::Memory;
|
||||
break;
|
||||
case Location::Storage:
|
||||
typeLoc = DataLocation::Storage;
|
||||
break;
|
||||
case Location::CallData:
|
||||
fatalTypeError(_variable.location(),
|
||||
"Variable cannot be declared as \"calldata\" (remove the \"calldata\" keyword)."
|
||||
);
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Unknown data location");
|
||||
}
|
||||
}
|
||||
isPointer = !_variable.isStateVariable();
|
||||
}
|
||||
|
||||
type = ref->copyForLocation(typeLoc, isPointer);
|
||||
}
|
||||
else if (varLoc != Location::Default && !ref)
|
||||
typeError(_variable.location(), "Storage location can only be given for array or struct types.");
|
||||
typeError(_variable.location(), "Data location can only be given for array or struct types.");
|
||||
|
||||
_variable.annotation().type = type;
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ void TypeChecker::annotateBaseConstructorArguments(
|
||||
|
||||
SourceLocation const* mainLocation = nullptr;
|
||||
SecondarySourceLocation ssl;
|
||||
|
||||
|
||||
if (
|
||||
_currentContract.location().contains(previousNode->location()) ||
|
||||
_currentContract.location().contains(_argumentNode->location())
|
||||
|
||||
@@ -656,7 +656,7 @@ private:
|
||||
class VariableDeclaration: public Declaration
|
||||
{
|
||||
public:
|
||||
enum Location { Default, Storage, Memory };
|
||||
enum Location { Default, Storage, Memory, CallData };
|
||||
|
||||
VariableDeclaration(
|
||||
SourceLocation const& _sourceLocation,
|
||||
|
||||
@@ -751,6 +751,8 @@ string ASTJsonConverter::location(VariableDeclaration::Location _location)
|
||||
return "storage";
|
||||
case VariableDeclaration::Location::Memory:
|
||||
return "memory";
|
||||
case VariableDeclaration::Location::CallData:
|
||||
return "calldata";
|
||||
default:
|
||||
solAssert(false, "Unknown declaration location.");
|
||||
}
|
||||
|
||||
@@ -1469,12 +1469,20 @@ string ReferenceType::stringForReferencePart() const
|
||||
string ReferenceType::identifierLocationSuffix() const
|
||||
{
|
||||
string id;
|
||||
if (location() == DataLocation::Storage)
|
||||
switch (location())
|
||||
{
|
||||
case DataLocation::Storage:
|
||||
id += "_storage";
|
||||
else if (location() == DataLocation::Memory)
|
||||
break;
|
||||
case DataLocation::Memory:
|
||||
id += "_memory";
|
||||
else
|
||||
break;
|
||||
case DataLocation::CallData:
|
||||
id += "_calldata";
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Unknown location returned by location()");
|
||||
}
|
||||
if (isPointer())
|
||||
id += "_ptr";
|
||||
return id;
|
||||
|
||||
@@ -592,11 +592,22 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
else if (!type)
|
||||
parserError(string("Location specifier needs explicit type name."));
|
||||
else
|
||||
location = (
|
||||
token == Token::Memory ?
|
||||
VariableDeclaration::Location::Memory :
|
||||
VariableDeclaration::Location::Storage
|
||||
);
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case Token::Storage:
|
||||
location = VariableDeclaration::Location::Storage;
|
||||
break;
|
||||
case Token::Memory:
|
||||
location = VariableDeclaration::Location::Memory;
|
||||
break;
|
||||
case Token::CallData:
|
||||
location = VariableDeclaration::Location::CallData;
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Unknown data location.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
@@ -173,6 +173,7 @@ namespace solidity
|
||||
K(Return, "return", 0) \
|
||||
K(Returns, "returns", 0) \
|
||||
K(Storage, "storage", 0) \
|
||||
K(CallData, "calldata", 0) \
|
||||
K(Struct, "struct", 0) \
|
||||
K(Throw, "throw", 0) \
|
||||
K(Using, "using", 0) \
|
||||
@@ -289,7 +290,7 @@ public:
|
||||
static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); }
|
||||
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
|
||||
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
|
||||
static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage; }
|
||||
static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage || op == CallData; }
|
||||
static bool isStateMutabilitySpecifier(Value op) { return op == Pure || op == Constant || op == View || op == Payable; }
|
||||
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
|
||||
static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
|
||||
@@ -348,7 +349,7 @@ public:
|
||||
unsigned int secondNumber() const { return m_secondNumber; }
|
||||
Token::Value token() const { return m_token; }
|
||||
///if tokValue is set to true, then returns the actual token type name, otherwise, returns full type
|
||||
std::string toString(bool const& tokenValue = false) const
|
||||
std::string toString(bool const& tokenValue = false) const
|
||||
{
|
||||
std::string name = Token::toString(m_token);
|
||||
if (tokenValue || (firstNumber() == 0 && secondNumber() == 0))
|
||||
|
||||
Reference in New Issue
Block a user