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 +++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') 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; } -- cgit v1.2.3 From 8862b3092bcdbcb8314ec27e2b11bf25fcc6346a Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Fri, 15 Jun 2018 12:30:28 +0200 Subject: C99 scoping rules by default --- libsolidity/analysis/ReferencesResolver.cpp | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index a051d7f9..58b659f7 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -48,9 +48,7 @@ bool ReferencesResolver::visit(Block const& _block) if (!m_resolveInsideCode) return false; m_experimental050Mode = _block.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); - // C99-scoped variables - if (m_experimental050Mode) - m_resolver.setScope(&_block); + m_resolver.setScope(&_block); return true; } @@ -59,9 +57,7 @@ void ReferencesResolver::endVisit(Block const& _block) if (!m_resolveInsideCode) return; - // C99-scoped variables - if (m_experimental050Mode) - m_resolver.setScope(_block.scope()); + m_resolver.setScope(_block.scope()); } bool ReferencesResolver::visit(ForStatement const& _for) @@ -69,9 +65,7 @@ bool ReferencesResolver::visit(ForStatement const& _for) if (!m_resolveInsideCode) return false; m_experimental050Mode = _for.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); - // C99-scoped variables - if (m_experimental050Mode) - m_resolver.setScope(&_for); + m_resolver.setScope(&_for); return true; } @@ -79,18 +73,16 @@ void ReferencesResolver::endVisit(ForStatement const& _for) { if (!m_resolveInsideCode) return; - if (m_experimental050Mode) - m_resolver.setScope(_for.scope()); + m_resolver.setScope(_for.scope()); } void ReferencesResolver::endVisit(VariableDeclarationStatement const& _varDeclStatement) { if (!m_resolveInsideCode) return; - if (m_experimental050Mode) - for (auto const& var: _varDeclStatement.declarations()) - if (var) - m_resolver.activateVariable(var->name()); + for (auto const& var: _varDeclStatement.declarations()) + if (var) + m_resolver.activateVariable(var->name()); } bool ReferencesResolver::visit(Identifier const& _identifier) @@ -99,9 +91,14 @@ bool ReferencesResolver::visit(Identifier const& _identifier) if (declarations.empty()) { string suggestions = m_resolver.similarNameSuggestions(_identifier.name()); - string errorMessage = - "Undeclared identifier." + - (suggestions.empty()? "": " Did you mean " + std::move(suggestions) + "?"); + string errorMessage = "Undeclared identifier."; + if (!suggestions.empty()) + { + if ("\"" + _identifier.name() + "\"" == suggestions) + errorMessage += " " + std::move(suggestions) + " is not (or not yet) visible at this point."; + else + errorMessage += " Did you mean " + std::move(suggestions) + "?"; + } declarationError(_identifier.location(), errorMessage); } else if (declarations.size() == 1) -- cgit v1.2.3 From a1f54f4e40811e526541f3a54f6a19dd42c8e688 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 11 Jul 2018 13:23:16 +0200 Subject: Require storage location. --- libsolidity/analysis/ReferencesResolver.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 58b659f7..dfcbf888 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -377,19 +377,10 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) { typeLoc = DataLocation::Storage; if (_variable.isLocalVariable()) - { - if (_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050)) - typeError( - _variable.location(), - "Data location must be specified as either \"memory\" or \"storage\"." - ); - else - m_errorReporter.warning( - _variable.location(), - "Variable is declared as a storage pointer. " - "Use an explicit \"storage\" keyword to silence this warning." - ); - } + typeError( + _variable.location(), + "Data location must be specified as either \"memory\" or \"storage\"." + ); } } else -- cgit v1.2.3 From c622a1e56c0a02b890b45fd15f1fb4cb9d119b3b Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Wed, 18 Jul 2018 17:20:26 +0200 Subject: Enforces data location of local mappings to storage. --- libsolidity/analysis/ReferencesResolver.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index dfcbf888..5815e3d2 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -404,9 +404,16 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) } isPointer = !_variable.isStateVariable(); } - type = ref->copyForLocation(typeLoc, isPointer); } + else if (dynamic_cast(type.get())) + { + if (_variable.isLocalVariable() && varLoc != Location::Storage) + typeError( + _variable.location(), + "Data location for mappings must be specified as \"storage\"." + ); + } else if (varLoc != Location::Default && !ref) typeError(_variable.location(), "Data location can only be given for array or struct types."); -- cgit v1.2.3 From 210fee571fb786751763e731f6fb107891e13383 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Mon, 30 Jul 2018 16:43:50 +0200 Subject: Fix crash when FunctionType has undeclared type as parameter --- libsolidity/analysis/ReferencesResolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 5815e3d2..a9a998b0 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -144,7 +144,7 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName) Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath()); if (!declaration) { - declarationError(_typeName.location(), "Identifier not found or not unique."); + fatalDeclarationError(_typeName.location(), "Identifier not found or not unique."); return; } -- cgit v1.2.3 From 5d9320c70b11b5ae1a44376451599732aa49dcde Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Tue, 3 Jul 2018 11:51:44 +0200 Subject: Disallow loos assembly in Solidity by permanently setting it to SyntaxError (from Warning) --- libsolidity/analysis/ReferencesResolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index a9a998b0..e058d917 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -277,7 +277,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) // Will be re-generated later with correct information // We use the latest EVM version because we will re-run it anyway. assembly::AsmAnalysisInfo analysisInfo; - boost::optional errorTypeForLoose = m_experimental050Mode ? Error::Type::SyntaxError : Error::Type::Warning; + boost::optional errorTypeForLoose = Error::Type::SyntaxError; assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations()); return false; } -- cgit v1.2.3 From 08e431f94e6f8fda05c6507e487dcbbf3c155aae Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 6 Aug 2018 11:48:48 +0100 Subject: Remove unused 050 variable in ReferencesResolver --- libsolidity/analysis/ReferencesResolver.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index e058d917..ba793933 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -47,7 +47,6 @@ bool ReferencesResolver::visit(Block const& _block) { if (!m_resolveInsideCode) return false; - m_experimental050Mode = _block.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); m_resolver.setScope(&_block); return true; } @@ -64,7 +63,6 @@ bool ReferencesResolver::visit(ForStatement const& _for) { if (!m_resolveInsideCode) return false; - m_experimental050Mode = _for.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); m_resolver.setScope(&_for); return true; } -- cgit v1.2.3 From 4c90ddf64ad22e2cae51d67269df3e326dbf4cb8 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 6 Aug 2018 18:03:17 +0200 Subject: libsolidity: Remove dead code wrt. VariableDeclaration::canHaveAutoType() Closes #4667 --- libsolidity/analysis/ReferencesResolver.cpp | 214 ++++++++++++++-------------- 1 file changed, 109 insertions(+), 105 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index ba793933..bbead87f 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -292,134 +292,138 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) if (_variable.annotation().type) return; + if (!_variable.typeName()) + { + // This can still happen in very unusual cases where a developer uses constructs, such as + // `var a;`, however, such code will have generated errors already. + // However, we cannot blindingly solAssert() for that here, as the TypeChecker (which is + // invoking ReferencesResolver) is generating it, so the error is most likely(!) generated + // after this step. + 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(type.get())) { - 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(type.get())) + bool isPointer = true; + if (_variable.isExternalCallableParameter()) { - bool isPointer = true; - if (_variable.isExternalCallableParameter()) + auto const& contract = dynamic_cast( + *dynamic_cast(*_variable.scope()).scope() + ); + if (contract.isLibrary()) { - auto const& contract = dynamic_cast( - *dynamic_cast(*_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::CallData && 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; + if (varLoc == Location::Memory) + fatalTypeError(_variable.location(), + "Location has to be calldata or storage for external " + "library functions (remove the \"memory\" keyword)." + ); } - else if (_variable.isCallableParameter() && dynamic_cast(*_variable.scope()).isPublic()) + else { - auto const& contract = dynamic_cast( - *dynamic_cast(*_variable.scope()).scope() + // force location of external function parameters (not return) to calldata + if (varLoc != Location::CallData && 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() && dynamic_cast(*_variable.scope()).isPublic()) + { + auto const& contract = dynamic_cast( + *dynamic_cast(*_variable.scope()).scope() + ); + // force locations of public or external function (return) parameters to memory + if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary()) + fatalTypeError(_variable.location(), + "Location has to be memory for publicly visible functions " + "(remove the \"storage\" or \"calldata\" keyword)." ); - // force locations of public or external function (return) parameters to memory - if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary()) + if (varLoc == Location::Default || !contract.isLibrary()) + typeLoc = DataLocation::Memory; + else + { + if (varLoc == Location::CallData) fatalTypeError(_variable.location(), - "Location has to be memory for publicly visible functions " - "(remove the \"storage\" or \"calldata\" keyword)." + "Location cannot be calldata for non-external functions " + "(remove the \"calldata\" keyword)." + ); + typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; + } + } + else + { + if (_variable.isConstant()) + { + if (varLoc != Location::Default && varLoc != Location::Memory) + fatalTypeError( + _variable.location(), + "Data location has to be \"memory\" (or unspecified) for constants." ); - if (varLoc == Location::Default || !contract.isLibrary()) + typeLoc = DataLocation::Memory; + } + else if (varLoc == Location::Default) + { + if (_variable.isCallableParameter()) typeLoc = DataLocation::Memory; else { - if (varLoc == Location::CallData) - fatalTypeError(_variable.location(), - "Location cannot be calldata for non-external functions " - "(remove the \"calldata\" keyword)." + typeLoc = DataLocation::Storage; + if (_variable.isLocalVariable()) + typeError( + _variable.location(), + "Data location must be specified as either \"memory\" or \"storage\"." ); - typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; } } else { - if (_variable.isConstant()) + switch (varLoc) { - if (varLoc != Location::Default && varLoc != Location::Memory) - fatalTypeError( - _variable.location(), - "Data location has to be \"memory\" (or unspecified) for constants." - ); + 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"); } - else if (varLoc == Location::Default) - { - if (_variable.isCallableParameter()) - typeLoc = DataLocation::Memory; - else - { - typeLoc = DataLocation::Storage; - if (_variable.isLocalVariable()) - typeError( - _variable.location(), - "Data location must be specified as either \"memory\" or \"storage\"." - ); - } - } - else - { - 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 (dynamic_cast(type.get())) - { - if (_variable.isLocalVariable() && varLoc != Location::Storage) - typeError( - _variable.location(), - "Data location for mappings must be specified as \"storage\"." - ); + isPointer = !_variable.isStateVariable(); } - else if (varLoc != Location::Default && !ref) - typeError(_variable.location(), "Data location can only be given for array or struct types."); - - _variable.annotation().type = type; + type = ref->copyForLocation(typeLoc, isPointer); } - else if (!_variable.canHaveAutoType()) - typeError(_variable.location(), "Explicit type needed."); - // otherwise we have a "var"-declaration whose type is resolved by the first assignment + else if (dynamic_cast(type.get())) + { + if (_variable.isLocalVariable() && varLoc != Location::Storage) + typeError( + _variable.location(), + "Data location for mappings must be specified as \"storage\"." + ); + } + else if (varLoc != Location::Default && !ref) + typeError(_variable.location(), "Data location can only be given for array or struct types."); + + _variable.annotation().type = type; } void ReferencesResolver::typeError(SourceLocation const& _location, string const& _description) -- cgit v1.2.3 From 296ba24f7f14811c5a5482457391d4f1afa49a87 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 7 Aug 2018 11:23:00 +0100 Subject: Do not crash on using _slot and _offset suffixes on their own --- libsolidity/analysis/ReferencesResolver.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index ba793933..5458c1b0 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -256,6 +256,11 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) string("_slot").size() : string("_offset").size() )); + if (realName.empty()) + { + declarationError(_identifier.location, "In variable names _slot and _offset can only be used as a suffix."); + return size_t(-1); + } declarations = m_resolver.nameFromCurrentScope(realName); } if (declarations.size() != 1) -- cgit v1.2.3 From 3c791d637d6bdf709ec272e6c8cf9ff51abd34ef Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 8 Aug 2018 15:55:41 +0100 Subject: Provide nicer error message when referencing overloaded references --- libsolidity/analysis/ReferencesResolver.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 501521f5..2cf09eff 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -264,7 +264,10 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) declarations = m_resolver.nameFromCurrentScope(realName); } if (declarations.size() != 1) + { + declarationError(_identifier.location, "Multiple matching identifiers. Resolving overloaded identifiers is not supported."); return size_t(-1); + } if (auto var = dynamic_cast(declarations.front())) if (var->isLocalVariable() && _crossesFunctionBoundary) { -- cgit v1.2.3 From c9ca083d141eeb54ee95a78e294a9ce5a53ebef3 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 9 Aug 2018 15:04:00 +0200 Subject: Fix data location of external reference parameters. --- libsolidity/analysis/ReferencesResolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 2cf09eff..fa0888dd 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -344,7 +344,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) "(remove the \"memory\" or \"storage\" keyword)." ); } - if (varLoc == Location::Default) + if (varLoc == Location::Default || varLoc == Location::CallData) typeLoc = DataLocation::CallData; else typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; -- cgit v1.2.3 From 683bce18690cc2790b68289278a5d84995472fda Mon Sep 17 00:00:00 2001 From: Chase McDermott Date: Tue, 7 Aug 2018 15:58:34 +0200 Subject: Refactor data location check. --- libsolidity/analysis/ReferencesResolver.cpp | 192 ++++++++++++---------------- 1 file changed, 83 insertions(+), 109 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index fa0888dd..f33de7b7 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -30,7 +30,10 @@ #include #include +#include + #include +#include using namespace std; using namespace dev; @@ -155,7 +158,10 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName) else if (ContractDefinition const* contract = dynamic_cast(declaration)) _typeName.annotation().type = make_shared(*contract); else + { + _typeName.annotation().type = make_shared(); typeError(_typeName.location(), "Name has to refer to a struct, enum or contract."); + } } void ReferencesResolver::endVisit(FunctionTypeName const& _typeName) @@ -166,13 +172,13 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName) case VariableDeclaration::Visibility::External: break; default: - typeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\"."); + fatalTypeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\"."); return; } if (_typeName.isPayable() && _typeName.visibility() != VariableDeclaration::Visibility::External) { - typeError(_typeName.location(), "Only external function types can be payable."); + fatalTypeError(_typeName.location(), "Only external function types can be payable."); return; } @@ -182,7 +188,7 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName) solAssert(t->annotation().type, "Type not set for parameter."); if (!t->annotation().type->canBeUsedExternally(false)) { - typeError(t->location(), "Internal type cannot be used for external function type."); + fatalTypeError(t->location(), "Internal type cannot be used for external function type."); return; } } @@ -300,6 +306,9 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) if (_variable.annotation().type) return; + if (_variable.isConstant() && !_variable.isStateVariable()) + m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables."); + if (!_variable.typeName()) { // This can still happen in very unusual cases where a developer uses constructs, such as @@ -309,127 +318,92 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) // after this step. return; } - - TypePointer type; - 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(type.get())) + + set allowedDataLocations = _variable.allowedDataLocations(); + if (!allowedDataLocations.count(varLoc)) { - bool isPointer = true; - if (_variable.isExternalCallableParameter()) + auto locationToString = [](VariableDeclaration::Location _location) -> string { - auto const& contract = dynamic_cast( - *dynamic_cast(*_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 + switch (_location) { - // force location of external function parameters (not return) to calldata - if (varLoc != Location::CallData && varLoc != Location::Default) - fatalTypeError(_variable.location(), - "Location has to be calldata for external functions " - "(remove the \"memory\" or \"storage\" keyword)." - ); + case Location::Memory: return "\"memory\""; + case Location::Storage: return "\"storage\""; + case Location::CallData: return "\"calldata\""; + case Location::Default: return "none"; } - if (varLoc == Location::Default || varLoc == Location::CallData) - typeLoc = DataLocation::CallData; - else - typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage; - } - else if (_variable.isCallableParameter() && dynamic_cast(*_variable.scope()).isPublic()) + return {}; + }; + + string errorString; + if (!_variable.hasReferenceOrMappingType()) + errorString = "Data location can only be specified for array, struct or mapping types"; + else { - auto const& contract = dynamic_cast( - *dynamic_cast(*_variable.scope()).scope() + errorString = "Data location must be " + + joinHumanReadable( + allowedDataLocations | boost::adaptors::transformed(locationToString), + ", ", + " or " ); - // force locations of public or external function (return) parameters to memory - if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary()) - fatalTypeError(_variable.location(), - "Location has to be memory for publicly visible functions " - "(remove the \"storage\" or \"calldata\" keyword)." - ); - if (varLoc == Location::Default || !contract.isLibrary()) - typeLoc = DataLocation::Memory; + if (_variable.isCallableParameter()) + errorString += + " for " + + string(_variable.isReturnParameter() ? "return " : "") + + "parameter in" + + string(_variable.isExternalCallableParameter() ? " external" : "") + + " function"; 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; - } + errorString += " for variable"; } - else + errorString += ", but " + locationToString(varLoc) + " was given."; + typeError(_variable.location(), errorString); + + solAssert(!allowedDataLocations.empty(), ""); + varLoc = *allowedDataLocations.begin(); + } + + // Find correct data location. + if (_variable.isEventParameter()) + { + solAssert(varLoc == Location::Default, ""); + typeLoc = DataLocation::Memory; + } + else if (_variable.isStateVariable()) + { + solAssert(varLoc == Location::Default, ""); + typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage; + } + else if ( + dynamic_cast(_variable.scope()) || + dynamic_cast(_variable.scope()) + ) + // The actual location will later be changed depending on how the type is used. + typeLoc = DataLocation::Storage; + else + switch (varLoc) { - if (_variable.isConstant()) - { - if (varLoc != Location::Default && varLoc != Location::Memory) - fatalTypeError( - _variable.location(), - "Data location has to be \"memory\" (or unspecified) for constants." - ); - typeLoc = DataLocation::Memory; - } - else if (varLoc == Location::Default) - { - if (_variable.isCallableParameter()) - typeLoc = DataLocation::Memory; - else - { - typeLoc = DataLocation::Storage; - if (_variable.isLocalVariable()) - typeError( - _variable.location(), - "Data location must be specified as either \"memory\" or \"storage\"." - ); - } - } - else - { - 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(); + case Location::Memory: + typeLoc = DataLocation::Memory; + break; + case Location::Storage: + typeLoc = DataLocation::Storage; + break; + case Location::CallData: + typeLoc = DataLocation::CallData; + break; + case Location::Default: + solAssert(!_variable.hasReferenceOrMappingType(), "Data location not properly set."); } - type = ref->copyForLocation(typeLoc, isPointer); - } - else if (dynamic_cast(type.get())) + + TypePointer type = _variable.typeName()->annotation().type; + if (auto ref = dynamic_cast(type.get())) { - if (_variable.isLocalVariable() && varLoc != Location::Storage) - typeError( - _variable.location(), - "Data location for mappings must be specified as \"storage\"." - ); + bool isPointer = !_variable.isStateVariable(); + type = ref->copyForLocation(typeLoc, isPointer); } - else if (varLoc != Location::Default && !ref) - typeError(_variable.location(), "Data location can only be given for array or struct types."); _variable.annotation().type = type; } -- cgit v1.2.3 From 551e0bf47cd0a1d1cb24a878f2309fd9f3253d00 Mon Sep 17 00:00:00 2001 From: Chase McDermott Date: Fri, 17 Aug 2018 18:09:31 -0500 Subject: Rename Location::Default to Location::Unspecified. --- libsolidity/analysis/ReferencesResolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f33de7b7..8750b47b 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -332,7 +332,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) case Location::Memory: return "\"memory\""; case Location::Storage: return "\"storage\""; case Location::CallData: return "\"calldata\""; - case Location::Default: return "none"; + case Location::Unspecified: return "none"; } return {}; }; @@ -368,12 +368,12 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) // Find correct data location. if (_variable.isEventParameter()) { - solAssert(varLoc == Location::Default, ""); + solAssert(varLoc == Location::Unspecified, ""); typeLoc = DataLocation::Memory; } else if (_variable.isStateVariable()) { - solAssert(varLoc == Location::Default, ""); + solAssert(varLoc == Location::Unspecified, ""); typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage; } else if ( @@ -394,7 +394,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) case Location::CallData: typeLoc = DataLocation::CallData; break; - case Location::Default: + case Location::Unspecified: solAssert(!_variable.hasReferenceOrMappingType(), "Data location not properly set."); } -- cgit v1.2.3 From 1ce3581a522a94d9e9a4a84cf8cb63f626e1a14f Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 6 Sep 2018 18:59:50 +0200 Subject: Accept ``address payable`` during parsing. --- libsolidity/analysis/ReferencesResolver.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 8750b47b..4b678c3b 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -112,7 +112,20 @@ bool ReferencesResolver::visit(Identifier const& _identifier) bool ReferencesResolver::visit(ElementaryTypeName const& _typeName) { - _typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName()); + if (!_typeName.annotation().type) + { + _typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName()); + if (_typeName.stateMutability().is_initialized()) + { + // for non-address types this was already caught by the parser + solAssert(_typeName.annotation().type->category() == Type::Category::Address, ""); + if (!( + *_typeName.stateMutability() == StateMutability::Payable || + *_typeName.stateMutability() == StateMutability::NonPayable + )) + m_errorReporter.typeError(_typeName.location(), "Address types can only be payable or non-payable."); + } + } return true; } -- cgit v1.2.3 From 12aaca16458861e9b622818d49a82c1a7026594e Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 5 Sep 2018 17:59:55 +0200 Subject: Add payable and non-payable state mutability to AddressType. --- libsolidity/analysis/ReferencesResolver.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 4b678c3b..8a576e2e 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -119,11 +119,19 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName) { // for non-address types this was already caught by the parser solAssert(_typeName.annotation().type->category() == Type::Category::Address, ""); - if (!( - *_typeName.stateMutability() == StateMutability::Payable || - *_typeName.stateMutability() == StateMutability::NonPayable - )) - m_errorReporter.typeError(_typeName.location(), "Address types can only be payable or non-payable."); + switch(*_typeName.stateMutability()) + { + case StateMutability::Payable: + case StateMutability::NonPayable: + _typeName.annotation().type = make_shared(*_typeName.stateMutability()); + break; + default: + m_errorReporter.typeError( + _typeName.location(), + "Address types can only be payable or non-payable." + ); + break; + } } } return true; -- cgit v1.2.3 From d821cbdff5a483b3f7a7bd07758bf5e11a7cd762 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Sat, 22 Sep 2018 00:18:22 +0200 Subject: Moves length check to reference resolver. --- libsolidity/analysis/ReferencesResolver.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 8a576e2e..30aa3d49 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -231,6 +231,8 @@ void ReferencesResolver::endVisit(Mapping const& _typeName) void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) { TypePointer baseType = _typeName.baseType().annotation().type; + auto arrayType = dynamic_cast(baseType.get()); + bool isFixedSizeArray = (arrayType && arrayType->isByteArray()) || !baseType->isDynamicallySized(); if (!baseType) { solAssert(!m_errorReporter.errors().empty(), ""); @@ -246,6 +248,8 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) RationalNumberType const* lengthType = dynamic_cast(lengthTypeGeneric.get()); if (!lengthType || !lengthType->mobileType()) fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression."); + else if (lengthType->isZero() && isFixedSizeArray) + fatalTypeError(length->location(), "Array with zero length specified."); else if (lengthType->isFractional()) fatalTypeError(length->location(), "Array with fractional length specified."); else if (lengthType->isNegative()) -- cgit v1.2.3 From e6d87e54c8cdf7c9111707770e995b486ec82460 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Sat, 22 Sep 2018 03:07:12 +0200 Subject: Simplifies zero-length check for fixed-size arrays. --- libsolidity/analysis/ReferencesResolver.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 30aa3d49..6217c5d1 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -231,8 +231,6 @@ void ReferencesResolver::endVisit(Mapping const& _typeName) void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) { TypePointer baseType = _typeName.baseType().annotation().type; - auto arrayType = dynamic_cast(baseType.get()); - bool isFixedSizeArray = (arrayType && arrayType->isByteArray()) || !baseType->isDynamicallySized(); if (!baseType) { solAssert(!m_errorReporter.errors().empty(), ""); @@ -243,12 +241,14 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) if (Expression const* length = _typeName.length()) { TypePointer lengthTypeGeneric = length->annotation().type; + auto arrayType = dynamic_cast(baseType.get()); + bool isByteOrFixedSizeArray = (arrayType && arrayType->isByteArray()) || !baseType->isDynamicallySized(); if (!lengthTypeGeneric) lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length); RationalNumberType const* lengthType = dynamic_cast(lengthTypeGeneric.get()); if (!lengthType || !lengthType->mobileType()) fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression."); - else if (lengthType->isZero() && isFixedSizeArray) + else if (lengthType->isZero() && isByteOrFixedSizeArray) fatalTypeError(length->location(), "Array with zero length specified."); else if (lengthType->isFractional()) fatalTypeError(length->location(), "Array with fractional length specified."); -- cgit v1.2.3 From 466e8f56e6fa7d816cc28028871b43f3a52fcdaa Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Wed, 26 Sep 2018 12:46:08 +0200 Subject: Removes unnecessary check of array type. --- libsolidity/analysis/ReferencesResolver.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 6217c5d1..81de3c43 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -241,14 +241,12 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) if (Expression const* length = _typeName.length()) { TypePointer lengthTypeGeneric = length->annotation().type; - auto arrayType = dynamic_cast(baseType.get()); - bool isByteOrFixedSizeArray = (arrayType && arrayType->isByteArray()) || !baseType->isDynamicallySized(); if (!lengthTypeGeneric) lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length); RationalNumberType const* lengthType = dynamic_cast(lengthTypeGeneric.get()); if (!lengthType || !lengthType->mobileType()) fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression."); - else if (lengthType->isZero() && isByteOrFixedSizeArray) + else if (lengthType->isZero()) fatalTypeError(length->location(), "Array with zero length specified."); else if (lengthType->isFractional()) fatalTypeError(length->location(), "Array with fractional length specified."); -- cgit v1.2.3 From 1304361b9c48438d5c55903492b5f11c3dac73e5 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 15 Oct 2018 11:58:51 +0200 Subject: Renaming namespace dev::julia to dev::yul. --- libsolidity/analysis/ReferencesResolver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 81de3c43..f62d9c3b 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -269,8 +269,8 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) // external references. ErrorList errors; ErrorReporter errorsIgnored(errors); - julia::ExternalIdentifierAccess::Resolver resolver = - [&](assembly::Identifier const& _identifier, julia::IdentifierContext, bool _crossesFunctionBoundary) { + yul::ExternalIdentifierAccess::Resolver resolver = + [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) { auto declarations = m_resolver.nameFromCurrentScope(_identifier.name); bool isSlot = boost::algorithm::ends_with(_identifier.name, "_slot"); bool isOffset = boost::algorithm::ends_with(_identifier.name, "_offset"); -- cgit v1.2.3 From 674e17c2a895eff6729357d8c10db709ac368b79 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 29 Oct 2018 15:12:02 +0100 Subject: Performance: Replace string by special single-copy YulString class. --- libsolidity/analysis/ReferencesResolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libsolidity/analysis/ReferencesResolver.cpp') diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f62d9c3b..2adc8e77 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -271,16 +271,16 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) ErrorReporter errorsIgnored(errors); yul::ExternalIdentifierAccess::Resolver resolver = [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) { - auto declarations = m_resolver.nameFromCurrentScope(_identifier.name); - bool isSlot = boost::algorithm::ends_with(_identifier.name, "_slot"); - bool isOffset = boost::algorithm::ends_with(_identifier.name, "_offset"); + auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str()); + bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot"); + bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset"); if (isSlot || isOffset) { // special mode to access storage variables if (!declarations.empty()) // the special identifier exists itself, we should not allow that. return size_t(-1); - string realName = _identifier.name.substr(0, _identifier.name.size() - ( + string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - ( isSlot ? string("_slot").size() : string("_offset").size() -- cgit v1.2.3