diff options
Diffstat (limited to 'libsolidity')
25 files changed, 250 insertions, 347 deletions
diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp index 6edf7986..483d08c8 100644 --- a/libsolidity/analysis/ControlFlowAnalyzer.cpp +++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp @@ -144,12 +144,12 @@ void ControlFlowAnalyzer::checkUnassignedStorageReturnValues( ssl.append("Problematic end of function:", _function.location()); } - m_errorReporter.warning( + m_errorReporter.typeError( returnVal->location(), - "This variable is of storage pointer type and might be returned without assignment. " - "This can cause storage corruption. Assign the variable (potentially from itself) " - "to remove this warning.", - ssl + ssl, + "This variable is of storage pointer type and might be returned without assignment and " + "could be used uninitialized. Assign the variable (potentially from itself) " + "to fix this error." ); } } diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 823378c7..c5c429ce 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -231,7 +231,7 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations( shared_ptr<FunctionType const> newFunctionType { d->functionType(false) }; if (!newFunctionType) newFunctionType = d->functionType(true); - return newFunctionType && functionType->hasEqualArgumentTypes(*newFunctionType); + return newFunctionType && functionType->hasEqualParameterTypes(*newFunctionType); } )) uniqueFunctions.push_back(declaration); @@ -295,10 +295,7 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res { setScope(contract); if (!resolveNamesAndTypes(*node, false)) - { success = false; - break; - } } if (!success) diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index a9a998b0..501521f5 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; } @@ -258,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) @@ -277,7 +280,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<Error::Type> errorTypeForLoose = m_experimental050Mode ? Error::Type::SyntaxError : Error::Type::Warning; + boost::optional<Error::Type> errorTypeForLoose = Error::Type::SyntaxError; assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations()); return false; } @@ -294,134 +297,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<ReferenceType const*>(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<ReferenceType const*>(type.get())) + bool isPointer = true; + if (_variable.isExternalCallableParameter()) { - bool isPointer = true; - if (_variable.isExternalCallableParameter()) + auto const& contract = dynamic_cast<ContractDefinition const&>( + *dynamic_cast<Declaration const&>(*_variable.scope()).scope() + ); + if (contract.isLibrary()) { - auto const& contract = dynamic_cast<ContractDefinition const&>( - *dynamic_cast<Declaration 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::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<Declaration const&>(*_variable.scope()).isPublic()) + else { - auto const& contract = dynamic_cast<ContractDefinition const&>( - *dynamic_cast<Declaration const&>(*_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<Declaration const&>(*_variable.scope()).isPublic()) + { + auto const& contract = dynamic_cast<ContractDefinition const&>( + *dynamic_cast<Declaration const&>(*_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)." ); - if (varLoc == Location::Default || !contract.isLibrary()) + 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." + ); + 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); + isPointer = !_variable.isStateVariable(); } - else if (dynamic_cast<MappingType const*>(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; + 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<MappingType const*>(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) diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index 4e8f54b5..24ec4643 100644 --- a/libsolidity/analysis/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -94,7 +94,6 @@ private: std::vector<ParameterList const*> m_returnParameters; bool const m_resolveInsideCode; bool m_errorOccurred = false; - bool m_experimental050Mode = false; }; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 8c84e4dc..6882a14f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -214,7 +214,7 @@ void TypeChecker::findDuplicateDefinitions(map<string, vector<T>> const& _defini SecondarySourceLocation ssl; for (size_t j = i + 1; j < overloads.size(); ++j) - if (FunctionType(*overloads[i]).hasEqualArgumentTypes(FunctionType(*overloads[j]))) + if (FunctionType(*overloads[i]).hasEqualParameterTypes(FunctionType(*overloads[j]))) { ssl.append("Other declaration is here:", overloads[j]->location()); reported.insert(j); @@ -252,7 +252,7 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont FunctionTypePointer funType = make_shared<FunctionType>(*function); auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag) { - return funType->hasEqualArgumentTypes(*_funAndFlag.first); + return funType->hasEqualParameterTypes(*_funAndFlag.first); }); if (it == overloads.end()) overloads.push_back(make_pair(funType, function->isImplemented())); @@ -404,7 +404,7 @@ void TypeChecker::checkFunctionOverride(FunctionDefinition const& function, Func FunctionType functionType(function); FunctionType superType(super); - if (!functionType.hasEqualArgumentTypes(superType)) + if (!functionType.hasEqualParameterTypes(superType)) return; if (!function.annotation().superFunction) @@ -475,7 +475,7 @@ void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _co for (auto const& it: externalDeclarations) for (size_t i = 0; i < it.second.size(); ++i) for (size_t j = i + 1; j < it.second.size(); ++j) - if (!it.second[i].second->hasEqualArgumentTypes(*it.second[j].second)) + if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second)) m_errorReporter.typeError( it.second[j].first->location(), "Function overload clash during conversion to external types for arguments." @@ -498,7 +498,12 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment) TupleType const& lhs = dynamic_cast<TupleType const&>(*type(_assignment.leftHandSide())); TupleType const& rhs = dynamic_cast<TupleType const&>(*type(_assignment.rightHandSide())); - bool fillRight = !lhs.components().empty() && (!lhs.components().back() || lhs.components().front()); + if (lhs.components().size() != rhs.components().size()) + { + solAssert(m_errorReporter.hasErrors(), ""); + return; + } + size_t storageToStorageCopies = 0; size_t toStorageCopies = 0; for (size_t i = 0; i < lhs.components().size(); ++i) @@ -506,10 +511,8 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment) ReferenceType const* ref = dynamic_cast<ReferenceType const*>(lhs.components()[i].get()); if (!ref || !ref->dataStoredIn(DataLocation::Storage) || ref->isPointer()) continue; - size_t rhsPos = fillRight ? i : rhs.components().size() - (lhs.components().size() - i); - solAssert(rhsPos < rhs.components().size(), ""); toStorageCopies++; - if (rhs.components()[rhsPos]->dataStoredIn(DataLocation::Storage)) + if (rhs.components()[i]->dataStoredIn(DataLocation::Storage)) storageToStorageCopies++; } if (storageToStorageCopies >= 1 && toStorageCopies >= 2) @@ -751,13 +754,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) return false; } -bool TypeChecker::visit(EnumDefinition const& _enum) -{ - if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface) - m_errorReporter.typeError(_enum.location(), "Enumerable cannot be declared in interfaces."); - return false; -} - void TypeChecker::visitManually( ModifierInvocation const& _modifier, vector<ContractDefinition const*> const& _bases @@ -817,6 +813,7 @@ void TypeChecker::visitManually( bool TypeChecker::visit(EventDefinition const& _eventDef) { + solAssert(_eventDef.visibility() > Declaration::Visibility::Internal, ""); unsigned numIndexed = 0; for (ASTPointer<VariableDeclaration> const& var: _eventDef.parameters()) { @@ -826,6 +823,15 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); if (!type(*var)->interfaceType(false)) m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type."); + if ( + !_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && + !typeSupportedByOldABIEncoder(*type(*var)) + ) + m_errorReporter.typeError( + var->location(), + "This type is only supported in the new experimental ABI encoder. " + "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." + ); } if (_eventDef.isAnonymous() && numIndexed > 4) m_errorReporter.typeError(_eventDef.location(), "More than 4 indexed arguments for anonymous event."); @@ -857,6 +863,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); Declaration const* declaration = ref->second.declaration; solAssert(!!declaration, ""); + bool requiresStorage = ref->second.isSlot || ref->second.isOffset; if (auto var = dynamic_cast<VariableDeclaration const*>(declaration)) { if (var->isConstant()) @@ -864,7 +871,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) m_errorReporter.typeError(_identifier.location, "Constant variables not supported by inline assembly."); return size_t(-1); } - else if (ref->second.isSlot || ref->second.isOffset) + else if (requiresStorage) { if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) { @@ -896,6 +903,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); } } + else if (requiresStorage) + { + m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); + return size_t(-1); + } else if (_context == julia::IdentifierContext::LValue) { m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly."); @@ -927,15 +939,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) }; solAssert(!_inlineAssembly.annotation().analysisInfo, ""); _inlineAssembly.annotation().analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - boost::optional<Error::Type> errorTypeForLoose = - m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050) ? - Error::Type::SyntaxError : - Error::Type::Warning; assembly::AsmAnalyzer analyzer( *_inlineAssembly.annotation().analysisInfo, m_errorReporter, m_evmVersion, - errorTypeForLoose, + Error::Type::SyntaxError, assembly::AsmFlavour::Loose, identifierAccess ); @@ -974,9 +982,13 @@ bool TypeChecker::visit(ForStatement const& _forStatement) void TypeChecker::endVisit(Return const& _return) { + ParameterList const* params = _return.annotation().functionReturnParameters; if (!_return.expression()) + { + if (params && !params->parameters().empty()) + m_errorReporter.typeError(_return.location(), "Return arguments required."); return; - ParameterList const* params = _return.annotation().functionReturnParameters; + } if (!params) { m_errorReporter.typeError(_return.location(), "Return arguments not allowed."); @@ -1038,7 +1050,10 @@ string createTupleDecl(vector<ASTPointer<VariableDeclaration>> const& _decls) vector<string> components; for (ASTPointer<VariableDeclaration> const& decl: _decls) if (decl) + { + solAssert(decl->annotation().type, ""); components.emplace_back(decl->annotation().type->toString(false) + " " + decl->name()); + } else components.emplace_back(); @@ -1056,6 +1071,9 @@ bool typeCanBeExpressed(vector<ASTPointer<VariableDeclaration>> const& decls) if (!decl) continue; + if (!decl->annotation().type) + return false; + if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type.get())) if ( functionType->kind() != FunctionType::Kind::Internal && @@ -1318,11 +1336,41 @@ bool TypeChecker::visit(Conditional const& _conditional) return false; } +void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& _expression) +{ + if (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(&_expression)) + { + auto const* tupleType = dynamic_cast<TupleType const*>(&_type); + auto const& types = tupleType ? tupleType->components() : vector<TypePointer> { _type.shared_from_this() }; + + solAssert(tupleExpression->components().size() == types.size(), ""); + for (size_t i = 0; i < types.size(); i++) + if (types[i]) + { + solAssert(!!tupleExpression->components()[i], ""); + checkExpressionAssignment(*types[i], *tupleExpression->components()[i]); + } + } + else if (_type.category() == Type::Category::Mapping) + { + bool isLocalOrReturn = false; + if (auto const* identifier = dynamic_cast<Identifier const*>(&_expression)) + if (auto const *variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration)) + if (variableDeclaration->isLocalOrReturn()) + isLocalOrReturn = true; + if (!isLocalOrReturn) + m_errorReporter.typeError(_expression.location(), "Mappings cannot be assigned to."); + } +} + bool TypeChecker::visit(Assignment const& _assignment) { requireLValue(_assignment.leftHandSide()); TypePointer t = type(_assignment.leftHandSide()); _assignment.annotation().type = t; + + checkExpressionAssignment(*t, _assignment.leftHandSide()); + if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t.get())) { if (_assignment.assignmentOperator() != Token::Assign) @@ -1339,11 +1387,6 @@ bool TypeChecker::visit(Assignment const& _assignment) if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide()).get())) checkDoubleStorageAssignment(_assignment); } - else if (t->category() == Type::Category::Mapping) - { - m_errorReporter.typeError(_assignment.location(), "Mappings cannot be assigned to."); - _assignment.rightHandSide().accept(*this); - } else if (_assignment.assignmentOperator() == Token::Assign) expectType(_assignment.rightHandSide(), *t); else diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 8dc6b376..b696de85 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -87,13 +87,15 @@ private: /// Checks (and warns) if a tuple assignment might cause unexpected overwrites in storage. /// Should only be called if the left hand side is tuple-typed. void checkDoubleStorageAssignment(Assignment const& _assignment); + // Checks whether the expression @arg _expression can be assigned from type @arg _type + // and reports an error, if not. + void checkExpressionAssignment(Type const& _type, Expression const& _expression); virtual void endVisit(InheritanceSpecifier const& _inheritance) override; virtual void endVisit(UsingForDirective const& _usingFor) override; virtual bool visit(StructDefinition const& _struct) override; virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(VariableDeclaration const& _variable) override; - virtual bool visit(EnumDefinition const& _enum) override; /// We need to do this manually because we want to pass the bases of the current contract in /// case this is a base constructor call. void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases); diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 7719d080..23797d52 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -347,15 +347,6 @@ string FunctionDefinition::externalSignature() const return FunctionType(*this).externalSignature(); } -string FunctionDefinition::fullyQualifiedName() const -{ - auto const* contract = dynamic_cast<ContractDefinition const*>(scope()); - solAssert(contract, "Enclosing scope of function definition was not set."); - - auto fname = name().empty() ? "<fallback>" : name(); - return sourceUnitName() + ":" + contract->name() + "." + fname; -} - FunctionDefinitionAnnotation& FunctionDefinition::annotation() const { if (!m_annotation) @@ -475,11 +466,6 @@ bool VariableDeclaration::isExternalCallableParameter() const return false; } -bool VariableDeclaration::canHaveAutoType() const -{ - return isLocalVariable() && !isCallableParameter(); -} - TypePointer VariableDeclaration::type() const { return annotation().type; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 9ed3b9aa..69c6fa05 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -206,7 +206,6 @@ public: bool isVisibleInDerivedContracts() const { return isVisibleInContract() && visibility() >= Visibility::Internal; } bool isVisibleAsLibraryMember() const { return visibility() >= Visibility::Internal; } - std::string fullyQualifiedName() const { return sourceUnitName() + ":" + name(); } virtual bool isLValue() const { return false; } virtual bool isPartOfExternalInterface() const { return false; } @@ -406,6 +405,8 @@ public: /// Returns the fallback function or nullptr if no fallback function was specified. FunctionDefinition const* fallbackFunction() const; + std::string fullyQualifiedName() const { return sourceUnitName() + ":" + name(); } + virtual TypePointer type() const override; virtual ContractDefinitionAnnotation& annotation() const override; @@ -619,7 +620,6 @@ public: std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; } std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); } Block const& body() const { solAssert(m_body, ""); return *m_body; } - std::string fullyQualifiedName() const; virtual bool isVisibleInContract() const override { return Declaration::isVisibleInContract() && !isConstructor() && !isFallback(); @@ -696,7 +696,6 @@ public: bool isExternalCallableParameter() const; /// @returns true if the type of the variable does not need to be specified, i.e. it is declared /// in the body of a function or modifier. - bool canHaveAutoType() const; bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } bool isConstant() const { return m_isConstant; } diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 7c04741d..72b20b3b 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -325,9 +325,6 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) std::vector<pair<string, Json::Value>> attributes = { make_pair("name", _node.name()), make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue), - // FIXME: remove with next breaking release - make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View), - make_pair("payable", _node.isPayable()), make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), make_pair("superFunction", idOrNull(_node.annotation().superFunction)), make_pair("visibility", Declaration::visibilityToString(_node.visibility())), @@ -418,11 +415,8 @@ bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) bool ASTJsonConverter::visit(FunctionTypeName const& _node) { setJsonNode(_node, "FunctionTypeName", { - make_pair("payable", _node.isPayable()), make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), - // FIXME: remove with next breaking release - make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View), make_pair("parameterTypes", toJson(*_node.parameterTypeList())), make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())), make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) diff --git a/libsolidity/ast/ExperimentalFeatures.h b/libsolidity/ast/ExperimentalFeatures.h index c66a3659..54aad573 100644 --- a/libsolidity/ast/ExperimentalFeatures.h +++ b/libsolidity/ast/ExperimentalFeatures.h @@ -31,7 +31,6 @@ enum class ExperimentalFeature { ABIEncoderV2, // new ABI encoder that makes use of Yul SMTChecker, - V050, // v0.5.0 breaking changes Test, TestOnlyAnalysis }; @@ -40,14 +39,12 @@ static const std::map<ExperimentalFeature, bool> ExperimentalFeatureOnlyAnalysis { { ExperimentalFeature::SMTChecker, true }, { ExperimentalFeature::TestOnlyAnalysis, true }, - { ExperimentalFeature::V050, true } }; static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames = { { "ABIEncoderV2", ExperimentalFeature::ABIEncoderV2 }, { "SMTChecker", ExperimentalFeature::SMTChecker }, - { "v0.5.0", ExperimentalFeature::V050 }, { "__test", ExperimentalFeature::Test }, { "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis }, }; diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 992d8fb6..349a59d4 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -169,15 +169,6 @@ pair<u256, unsigned> const* StorageOffsets::offset(size_t _index) const return nullptr; } -MemberList& MemberList::operator=(MemberList&& _other) -{ - solAssert(&_other != this, ""); - - m_memberTypes = move(_other.m_memberTypes); - m_storageOffsets = move(_other.m_storageOffsets); - return *this; -} - void MemberList::combine(MemberList const & _other) { m_memberTypes += _other.m_memberTypes; @@ -263,6 +254,17 @@ string Type::escapeIdentifier(string const& _identifier) return ret; } +string Type::identifier() const +{ + string ret = escapeIdentifier(richIdentifier()); + solAssert(ret.find_first_of("0123456789") != 0, "Identifier cannot start with a number."); + solAssert( + ret.find_first_not_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMONPQRSTUVWXYZ_$") == string::npos, + "Identifier contains invalid characters." + ); + return ret; +} + TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type) { solAssert(Token::isElementaryTypeName(_type.token()), @@ -1146,7 +1148,14 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ string RationalNumberType::richIdentifier() const { - return "t_rational_" + m_value.numerator().str() + "_by_" + m_value.denominator().str(); + // rational seemingly will put the sign always on the numerator, + // but let just make it deterministic here. + bigint numerator = abs(m_value.numerator()); + bigint denominator = abs(m_value.denominator()); + if (m_value < 0) + return "t_rational_minus_" + numerator.str() + "_by_" + denominator.str(); + else + return "t_rational_" + numerator.str() + "_by_" + denominator.str(); } bool RationalNumberType::operator==(Type const& _other) const @@ -1871,7 +1880,7 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con continue; auto memberType = dynamic_cast<FunctionType const*>(member.type.get()); solAssert(!!memberType, "Override changes type."); - if (!memberType->hasEqualArgumentTypes(*functionType)) + if (!memberType->hasEqualParameterTypes(*functionType)) continue; functionWithEqualArgumentsFound = true; break; @@ -2295,16 +2304,14 @@ TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) cons { solAssert(!!_targetType, ""); TypePointers const& targetComponents = dynamic_cast<TupleType const&>(*_targetType).components(); - bool fillRight = !targetComponents.empty() && (!targetComponents.back() || targetComponents.front()); + solAssert(components().size() == targetComponents.size(), ""); TypePointers tempComponents(targetComponents.size()); - for (size_t i = 0; i < min(targetComponents.size(), components().size()); ++i) + for (size_t i = 0; i < targetComponents.size(); ++i) { - size_t si = fillRight ? i : components().size() - i - 1; - size_t ti = fillRight ? i : targetComponents.size() - i - 1; - if (components()[si] && targetComponents[ti]) + if (components()[i] && targetComponents[i]) { - tempComponents[ti] = components()[si]->closestTemporaryType(targetComponents[ti]); - solAssert(tempComponents[ti], ""); + tempComponents[i] = components()[i]->closestTemporaryType(targetComponents[i]); + solAssert(tempComponents[i], ""); } } return make_shared<TupleType>(tempComponents); @@ -2825,7 +2832,7 @@ bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePoin ); } -bool FunctionType::hasEqualArgumentTypes(FunctionType const& _other) const +bool FunctionType::hasEqualParameterTypes(FunctionType const& _other) const { if (m_parameterTypes.size() != _other.m_parameterTypes.size()) return false; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 12029a4e..1fa2b2f5 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -95,9 +95,7 @@ public: using MemberMap = std::vector<Member>; - MemberList() {} explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {} - MemberList& operator=(MemberList&& _other); void combine(MemberList const& _other); TypePointer memberType(std::string const& _name) const { @@ -132,6 +130,8 @@ private: mutable std::unique_ptr<StorageOffsets> m_storageOffsets; }; +static_assert(std::is_nothrow_move_constructible<MemberList>::value, "MemberList should be noexcept move constructible"); + /** * Abstract base class that forms the root of the type hierarchy. */ @@ -172,7 +172,7 @@ public: /// only if they have the same identifier. /// The identifier should start with "t_". /// Will not contain any character which would be invalid as an identifier. - std::string identifier() const { return escapeIdentifier(richIdentifier()); } + std::string identifier() const; /// More complex identifier strings use "parentheses", where $_ is interpreted as as /// "opening parenthesis", _$ as "closing parenthesis", _$_ as "comma" and any $ that @@ -1035,7 +1035,7 @@ public: /// expression the function is called on. bool canTakeArguments(TypePointers const& _arguments, TypePointer const& _selfType = TypePointer()) const; /// @returns true if the types of parameters are equal (doesn't check return parameter types) - bool hasEqualArgumentTypes(FunctionType const& _other) const; + bool hasEqualParameterTypes(FunctionType const& _other) const; /// @returns true if the ABI is used for this call (only meaningful for external calls) bool isBareCall() const; diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 1ce77d67..dda77958 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -228,7 +228,8 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) if (type.numBytes() == 32) templ("body", "cleaned := value"); else if (type.numBytes() == 0) - templ("body", "cleaned := 0"); + // This is disallowed in the type system. + solAssert(false, ""); else { size_t numBits = type.numBytes() * 8; diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index d3afada5..55f1d252 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -46,19 +46,6 @@ void Compiler::compileContract( m_context.optimise(m_optimize, m_optimizeRuns); } -void Compiler::compileClone( - ContractDefinition const& _contract, - map<ContractDefinition const*, eth::Assembly const*> const& _contracts -) -{ - solAssert(!_contract.isLibrary(), ""); - ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize); - ContractCompiler cloneCompiler(&runtimeCompiler, m_context, m_optimize); - m_runtimeSub = cloneCompiler.compileClone(_contract, _contracts); - - m_context.optimise(m_optimize, m_optimizeRuns); -} - eth::AssemblyItem Compiler::functionEntryLabel(FunctionDefinition const& _function) const { return m_runtimeContext.functionEntryLabelIfExists(_function); diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index f6865d75..4028ae63 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -50,12 +50,6 @@ public: std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts, bytes const& _metadata ); - /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given - /// contract at runtime, but contains the full creation-time code. - void compileClone( - ContractDefinition const& _contract, - std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts - ); /// @returns Entire assembly. eth::Assembly const& assembly() const { return m_context.assembly(); } /// @returns The entire assembled object (with constructor). diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 3b1b4ec0..71b615b8 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -411,7 +411,7 @@ FunctionDefinition const& CompilerContext::resolveVirtualFunction( if ( function->name() == name && !function->isConstructor() && - FunctionType(*function).hasEqualArgumentTypes(functionType) + FunctionType(*function).hasEqualParameterTypes(functionType) ) return *function; solAssert(false, "Super function " + name + " not found."); diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index bd3ec8f5..b30851fb 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -947,20 +947,12 @@ void CompilerUtils::convertType( { TupleType const& sourceTuple = dynamic_cast<TupleType const&>(_typeOnStack); TupleType const& targetTuple = dynamic_cast<TupleType const&>(_targetType); - // fillRight: remove excess values at right side, !fillRight: remove eccess values at left side - bool fillRight = !targetTuple.components().empty() && ( - !targetTuple.components().back() || - targetTuple.components().front() - ); + solAssert(targetTuple.components().size() == sourceTuple.components().size(), ""); unsigned depth = sourceTuple.sizeOnStack(); for (size_t i = 0; i < sourceTuple.components().size(); ++i) { TypePointer sourceType = sourceTuple.components()[i]; - TypePointer targetType; - if (fillRight && i < targetTuple.components().size()) - targetType = targetTuple.components()[i]; - else if (!fillRight && targetTuple.components().size() + i >= sourceTuple.components().size()) - targetType = targetTuple.components()[targetTuple.components().size() - (sourceTuple.components().size() - i)]; + TypePointer targetType = targetTuple.components()[i]; if (!sourceType) { solAssert(!targetType, ""); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 2fffcf76..02274d60 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -94,27 +94,6 @@ size_t ContractCompiler::compileConstructor( } } -size_t ContractCompiler::compileClone( - ContractDefinition const& _contract, - map<ContractDefinition const*, eth::Assembly const*> const& _contracts -) -{ - initializeContext(_contract, _contracts); - - appendInitAndConstructorCode(_contract); - - //@todo determine largest return size of all runtime functions - auto runtimeSub = m_context.addSubroutine(cloneRuntime()); - - // stack contains sub size - m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY; - m_context << u256(0) << Instruction::RETURN; - - appendMissingFunctions(); - - return size_t(runtimeSub.data()); -} - void ContractCompiler::initializeContext( ContractDefinition const& _contract, map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts @@ -980,29 +959,6 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType); } -eth::AssemblyPointer ContractCompiler::cloneRuntime() const -{ - eth::Assembly a; - a << Instruction::CALLDATASIZE; - a << u256(0) << Instruction::DUP1 << Instruction::CALLDATACOPY; - //@todo adjust for larger return values, make this dynamic. - a << u256(0x20) << u256(0) << Instruction::CALLDATASIZE; - a << u256(0); - // this is the address which has to be substituted by the linker. - //@todo implement as special "marker" AssemblyItem. - a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); - a << u256(eth::GasCosts::callGas(m_context.evmVersion()) + 10) << Instruction::GAS << Instruction::SUB; - a << Instruction::DELEGATECALL; - //Propagate error condition (if DELEGATECALL pushes 0 on stack). - a << Instruction::ISZERO; - a << Instruction::ISZERO; - eth::AssemblyItem afterTag = a.appendJumpI().tag(); - a << Instruction::INVALID << afterTag; - //@todo adjust for larger return values, make this dynamic. - a << u256(0x20) << u256(0) << Instruction::RETURN; - return make_shared<eth::Assembly>(a); -} - void ContractCompiler::popScopedVariables(ASTNode const* _node) { unsigned blockHeight = m_scopeStackHeight.at(m_modifierDepth).at(_node); diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 8516ec2c..5fa650b1 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -56,13 +56,6 @@ public: ContractDefinition const& _contract, std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts ); - /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given - /// contract at runtime, but contains the full creation-time code. - /// @returns the identifier of the runtime sub-assembly. - size_t compileClone( - ContractDefinition const& _contract, - std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts - ); private: /// Registers the non-function objects inside the contract with the context and stores the basic @@ -122,9 +115,6 @@ private: void appendStackVariableInitialisation(VariableDeclaration const& _variable); void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); - /// @returns the runtime assembly for clone contracts. - eth::AssemblyPointer cloneRuntime() const; - /// Frees the variables of a certain scope (to be used when leaving). void popScopedVariables(ASTNode const* _node); diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp index 17b50a38..88c1e56a 100644 --- a/libsolidity/formal/SMTChecker.cpp +++ b/libsolidity/formal/SMTChecker.cpp @@ -375,8 +375,14 @@ void SMTChecker::endVisit(Identifier const& _identifier) } else if (SSAVariable::isSupportedType(_identifier.annotation().type->category())) { - VariableDeclaration const& decl = dynamic_cast<VariableDeclaration const&>(*(_identifier.annotation().referencedDeclaration)); - defineExpr(_identifier, currentValue(decl)); + if (VariableDeclaration const* decl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration)) + defineExpr(_identifier, currentValue(*decl)); + else + // TODO: handle MagicVariableDeclaration here + m_errorReporter.warning( + _identifier.location(), + "Assertion checker does not yet support the type of this variable." + ); } else if (FunctionType const* fun = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get())) { diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 011ca4dc..9a0110cf 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -57,7 +57,7 @@ bool AsmAnalyzer::operator()(Label const& _label) solAssert(!_label.name.empty(), ""); checkLooseFeature( _label.location, - "The use of labels is deprecated. Please use \"if\", \"switch\", \"for\" or function calls instead." + "The use of labels is disallowed. Please use \"if\", \"switch\", \"for\" or function calls instead." ); m_info.stackHeightInfo[&_label] = m_stackHeight; warnOnInstructions(solidity::Instruction::JUMPDEST, _label.location); @@ -68,7 +68,7 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction) { checkLooseFeature( _instruction.location, - "The use of non-functional instructions is deprecated. Please use functional notation instead." + "The use of non-functional instructions is disallowed. Please use functional notation instead." ); auto const& info = instructionInfo(_instruction.instruction); m_stackHeight += info.ret - info.args; @@ -201,7 +201,7 @@ bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment) { checkLooseFeature( _assignment.location, - "The use of stack assignment is deprecated. Please use assignment in functional notation instead." + "The use of stack assignment is disallowed. Please use assignment in functional notation instead." ); bool success = checkAssignment(_assignment.variableName, size_t(-1)); m_info.stackHeightInfo[&_assignment] = m_stackHeight; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index a7a3fe7a..836e30d2 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -329,7 +329,6 @@ void CompilerStack::link() { contract.second.object.link(m_libraries); contract.second.runtimeObject.link(m_libraries); - contract.second.cloneObject.link(m_libraries); } } @@ -408,11 +407,6 @@ eth::LinkerObject const& CompilerStack::runtimeObject(string const& _contractNam return contract(_contractName).runtimeObject; } -eth::LinkerObject const& CompilerStack::cloneObject(string const& _contractName) const -{ - return contract(_contractName).cloneObject; -} - /// FIXME: cache this string string CompilerStack::assemblyString(string const& _contractName, StringMap _sourceCodes) const { @@ -583,7 +577,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string for (auto const& node: _ast.nodes()) if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get())) { - string importPath = absolutePath(import->path(), _sourcePath); + string importPath = dev::absolutePath(import->path(), _sourcePath); // The current value of `path` is the absolute path as seen from this source file. // We first have to apply remappings before we can store the actual absolute path // as seen globally. @@ -626,8 +620,8 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context for (auto const& redir: m_remappings) { - string context = sanitizePath(redir.context); - string prefix = sanitizePath(redir.prefix); + string context = dev::sanitizePath(redir.context); + string prefix = dev::sanitizePath(redir.prefix); // Skip if current context is closer if (context.length() < longestContext) @@ -644,7 +638,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context longestContext = context.length(); longestPrefix = prefix.length(); - bestMatchTarget = sanitizePath(redir.target); + bestMatchTarget = dev::sanitizePath(redir.target); } string path = bestMatchTarget; path.append(_path.begin() + longestPrefix, _path.end()); @@ -681,23 +675,6 @@ void CompilerStack::resolveImports() swap(m_sourceOrder, sourceOrder); } -string CompilerStack::absolutePath(string const& _path, string const& _reference) -{ - using path = boost::filesystem::path; - path p(_path); - // Anything that does not start with `.` is an absolute path. - if (p.begin() == p.end() || (*p.begin() != "." && *p.begin() != "..")) - return _path; - path result(_reference); - result.remove_filename(); - for (path::iterator it = p.begin(); it != p.end(); ++it) - if (*it == "..") - result = result.parent_path(); - else if (*it != ".") - result /= *it; - return result.generic_string(); -} - namespace { bool onlySafeExperimentalFeaturesActivated(set<ExperimentalFeature> const& features) @@ -767,23 +744,6 @@ void CompilerStack::compileContract( } _compiledContracts[compiledContract.contract] = &compiler->assembly(); - - try - { - if (!_contract.isLibrary()) - { - Compiler cloneCompiler(m_evmVersion, m_optimize, m_optimizeRuns); - cloneCompiler.compileClone(_contract, _compiledContracts); - compiledContract.cloneObject = cloneCompiler.assembledObject(); - } - } - catch (eth::AssemblyException const&) - { - // In some cases (if the constructor requests a runtime function), it is not - // possible to compile the clone. - - // TODO: Report error / warning - } } string const CompilerStack::lastContractName() const diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 7b144660..2234a8c9 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -36,7 +36,6 @@ #include <json/json.h> #include <boost/noncopyable.hpp> -#include <boost/filesystem.hpp> #include <ostream> #include <string> @@ -190,12 +189,6 @@ public: /// @returns the runtime object for the contract. eth::LinkerObject const& runtimeObject(std::string const& _contractName) const; - /// @returns the bytecode of a contract that uses an already deployed contract via DELEGATECALL. - /// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to - /// substituted by the actual address. Note that this sequence starts end ends in three X - /// characters but can contain anything in between. - eth::LinkerObject const& cloneObject(std::string const& _contractName) const; - /// @returns normal contract assembly items eth::AssemblyItems const* assemblyItems(std::string const& _contractName) const; @@ -258,7 +251,6 @@ private: std::shared_ptr<Compiler> compiler; eth::LinkerObject object; ///< Deployment object (includes the runtime sub-object). eth::LinkerObject runtimeObject; ///< Runtime object. - eth::LinkerObject cloneObject; ///< Clone object (deprecated). std::string metadata; ///< The metadata json that will be hashed into the chain. mutable std::unique_ptr<Json::Value const> abi; mutable std::unique_ptr<Json::Value const> userDocumentation; @@ -274,12 +266,6 @@ private: std::string applyRemapping(std::string const& _path, std::string const& _context); void resolveImports(); - /// @returns the absolute path corresponding to @a _path relative to @a _reference. - static std::string absolutePath(std::string const& _path, std::string const& _reference); - - /// Helper function to return path converted strings. - static std::string sanitizePath(std::string const& _path) { return boost::filesystem::path(_path).generic_string(); } - /// @returns true if the contract is requested to be compiled. bool isRequestedContract(ContractDefinition const& _contract) const; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 8339780f..58b84163 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -567,7 +567,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) return output; } -Json::Value StandardCompiler::compile(Json::Value const& _input) +Json::Value StandardCompiler::compile(Json::Value const& _input) noexcept { try { @@ -591,7 +591,7 @@ Json::Value StandardCompiler::compile(Json::Value const& _input) } } -string StandardCompiler::compile(string const& _input) +string StandardCompiler::compile(string const& _input) noexcept { Json::Value input; string errors; diff --git a/libsolidity/interface/StandardCompiler.h b/libsolidity/interface/StandardCompiler.h index 2772394a..fc9c3a59 100644 --- a/libsolidity/interface/StandardCompiler.h +++ b/libsolidity/interface/StandardCompiler.h @@ -47,10 +47,10 @@ public: /// Sets all input parameters according to @a _input which conforms to the standardized input /// format, performs compilation and returns a standardized output. - Json::Value compile(Json::Value const& _input); + Json::Value compile(Json::Value const& _input) noexcept; /// Parses input as JSON and peforms the above processing steps, returning a serialized JSON /// output. Parsing errors are returned as regular errors. - std::string compile(std::string const& _input); + std::string compile(std::string const& _input) noexcept; private: Json::Value compileInternal(Json::Value const& _input); |