From b7cafcbdf95c807f46fc07f4788d82981b7112b4 Mon Sep 17 00:00:00 2001 From: mingchuan Date: Wed, 23 May 2018 12:31:20 +0800 Subject: Allow using `calldata` keyword to specify data location --- libsolidity/analysis/ReferencesResolver.cpp | 38 +++++++++++++++++++++++------ libsolidity/analysis/TypeChecker.cpp | 2 +- libsolidity/ast/AST.h | 2 +- libsolidity/ast/ASTJsonConverter.cpp | 2 ++ libsolidity/ast/Types.cpp | 14 ++++++++--- libsolidity/parsing/Parser.cpp | 21 ++++++++++++---- libsolidity/parsing/Token.h | 5 ++-- 7 files changed, 65 insertions(+), 19 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f91eaf6e..a051d7f9 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -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(*_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; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 30302908..60cde33c 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -351,7 +351,7 @@ void TypeChecker::annotateBaseConstructorArguments( SourceLocation const* mainLocation = nullptr; SecondarySourceLocation ssl; - + if ( _currentContract.location().contains(previousNode->location()) || _currentContract.location().contains(_argumentNode->location()) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index fa0d6921..d703ae53 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -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, diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index b8e00b60..b7855668 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -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."); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 59668e1d..8620f283 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -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; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index e2e1eebc..aec9ebbb 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -592,11 +592,22 @@ ASTPointer 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; diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index 4d7a7bc6..4d456550 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -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)) -- cgit v1.2.3