diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.cpp | 6 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 5 | ||||
-rw-r--r-- | libsolidity/analysis/SyntaxChecker.cpp | 9 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 47 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h | 4 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 41 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 2 | ||||
-rw-r--r-- | libsolidity/codegen/ABIFunctions.cpp | 34 | ||||
-rw-r--r-- | libsolidity/codegen/ArrayUtils.cpp | 3 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 21 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 3 | ||||
-rw-r--r-- | libsolidity/formal/Z3Interface.cpp | 9 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 6 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 11 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 11 | ||||
-rw-r--r-- | libsolidity/interface/GasEstimator.cpp | 2 | ||||
-rw-r--r-- | libsolidity/interface/StandardCompiler.cpp | 19 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 1 |
18 files changed, 192 insertions, 42 deletions
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 523e7176..5d010693 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -647,10 +647,12 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio bool warnAboutShadowing = true; // Do not warn about shadowing for structs and enums because their members are - // not accessible without prefixes. + // not accessible without prefixes. Also do not warn about event parameters + // because they don't participate in any proper scope. if ( dynamic_cast<StructDefinition const*>(m_currentScope) || - dynamic_cast<EnumDefinition const*>(m_currentScope) + dynamic_cast<EnumDefinition const*>(m_currentScope) || + dynamic_cast<EventDefinition const*>(m_currentScope) ) warnAboutShadowing = false; // Do not warn about the constructor shadowing the contract. diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 8f07d43a..20016112 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -149,8 +149,10 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) if (!length->annotation().type) ConstantEvaluator e(*length); auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get()); - if (!lengthType || lengthType->isFractional()) + if (!lengthType || !lengthType->mobileType()) fatalTypeError(length->location(), "Invalid array length, expected integer literal."); + else if (lengthType->isFractional()) + fatalTypeError(length->location(), "Array with fractional length specified."); else if (lengthType->isNegative()) fatalTypeError(length->location(), "Array with negative length specified."); else @@ -347,4 +349,3 @@ void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location, m_errorOccurred = true; m_errorReporter.fatalDeclarationError(_location, _description); } - diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 187eb26f..0ca4b86c 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -182,8 +182,15 @@ bool SyntaxChecker::visit(Throw const& _throwStatement) bool SyntaxChecker::visit(UnaryOperation const& _operation) { + bool const v050 = m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeature::V050); + if (_operation.getOperator() == Token::Add) - m_errorReporter.warning(_operation.location(), "Use of unary + is deprecated."); + { + if (v050) + m_errorReporter.syntaxError(_operation.location(), "Use of unary + is deprecated."); + else + m_errorReporter.warning(_operation.location(), "Use of unary + is deprecated."); + } return true; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 43930125..b2a88059 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -75,6 +75,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract) ASTNode::listAccept(_contract.baseContracts(), *this); checkContractDuplicateFunctions(_contract); + checkContractDuplicateEvents(_contract); checkContractIllegalOverrides(_contract); checkContractAbstractFunctions(_contract); checkContractAbstractConstructors(_contract); @@ -183,9 +184,27 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con msg ); } - for (auto const& it: functions) + + findDuplicateDefinitions(functions, "Function with same name and arguments defined twice."); +} + +void TypeChecker::checkContractDuplicateEvents(ContractDefinition const& _contract) +{ + /// Checks that two events with the same name defined in this contract have different + /// argument types + map<string, vector<EventDefinition const*>> events; + for (EventDefinition const* event: _contract.events()) + events[event->name()].push_back(event); + + findDuplicateDefinitions(events, "Event with same name and arguments defined twice."); +} + +template <class T> +void TypeChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions, string _message) +{ + for (auto const& it: _definitions) { - vector<FunctionDefinition const*> const& overloads = it.second; + vector<T> const& overloads = it.second; set<size_t> reported; for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i) { @@ -200,18 +219,17 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con if (ssl.infos.size() > 0) { - string msg = "Function with same name and arguments defined twice."; size_t occurrences = ssl.infos.size(); if (occurrences > 32) { ssl.infos.resize(32); - msg += " Truncated from " + boost::lexical_cast<string>(occurrences) + " to the first 32 occurrences."; + _message += " Truncated from " + boost::lexical_cast<string>(occurrences) + " to the first 32 occurrences."; } m_errorReporter.declarationError( overloads[i]->location(), ssl, - msg + _message ); } } @@ -627,14 +645,23 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (!allowed) m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented."); } + if (!_variable.value()) m_errorReporter.typeError(_variable.location(), "Uninitialized \"constant\" variable."); else if (!_variable.value()->annotation().isPure) - m_errorReporter.warning( - _variable.value()->location(), - "Initial value for constant variable has to be compile-time constant. " - "This will fail to compile with the next breaking version change." - ); + { + if (_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050)) + m_errorReporter.typeError( + _variable.value()->location(), + "Initial value for constant variable has to be compile-time constant." + ); + else + m_errorReporter.warning( + _variable.value()->location(), + "Initial value for constant variable has to be compile-time constant. " + "This will fail to compile with the next breaking version change." + ); + } } if (!_variable.isStateVariable()) { diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 0c6f54d3..abe6dac1 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -61,6 +61,7 @@ private: /// Checks that two functions defined in this contract with the same name have different /// arguments and that there is at most one constructor. void checkContractDuplicateFunctions(ContractDefinition const& _contract); + void checkContractDuplicateEvents(ContractDefinition const& _contract); void checkContractIllegalOverrides(ContractDefinition const& _contract); /// Reports a type error with an appropiate message if overriden function signature differs. /// Also stores the direct super function in the AST annotations. @@ -108,6 +109,9 @@ private: virtual void endVisit(ElementaryTypeNameExpression const& _expr) override; virtual void endVisit(Literal const& _literal) override; + template <class T> + void findDuplicateDefinitions(std::map<std::string, std::vector<T>> const& _definitions, std::string _message); + bool contractDependenciesAreCyclic( ContractDefinition const& _contract, std::set<ContractDefinition const*> const& _seenContracts = std::set<ContractDefinition const*>() diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index ebf2cd8b..a3cbe50a 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -89,7 +89,7 @@ pair<u256, unsigned> const* StorageOffsets::offset(size_t _index) const MemberList& MemberList::operator=(MemberList&& _other) { - assert(&_other != this); + solAssert(&_other != this, ""); m_memberTypes = move(_other.m_memberTypes); m_storageOffsets = move(_other.m_storageOffsets); @@ -1618,8 +1618,7 @@ string ContractType::canonicalName() const MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) const { - // All address members and all interface functions - MemberList::MemberMap members(IntegerType(160, IntegerType::Modifier::Address).nativeMembers(nullptr)); + MemberList::MemberMap members; if (m_super) { // add the most derived of all functions which are visible in derived contracts @@ -1661,9 +1660,45 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) con &it.second->declaration() )); } + addNonConflictingAddressMembers(members); return members; } +void ContractType::addNonConflictingAddressMembers(MemberList::MemberMap& _members) +{ + MemberList::MemberMap addressMembers = IntegerType(160, IntegerType::Modifier::Address).nativeMembers(nullptr); + for (auto const& addressMember: addressMembers) + { + bool clash = false; + for (auto const& member: _members) + { + if ( + member.name == addressMember.name && + ( + // Members with different types are not allowed + member.type->category() != addressMember.type->category() || + // Members must overload functions without clash + ( + member.type->category() == Type::Category::Function && + dynamic_cast<FunctionType const&>(*member.type).hasEqualArgumentTypes(dynamic_cast<FunctionType const&>(*addressMember.type)) + ) + ) + ) + { + clash = true; + break; + } + } + + if (!clash) + _members.push_back(MemberList::Member( + addressMember.name, + addressMember.type, + addressMember.declaration + )); + } +} + shared_ptr<FunctionType const> const& ContractType::newExpressionType() const { if (!m_constructorType) diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 8ba55521..ce29975e 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -716,6 +716,8 @@ public: std::vector<std::tuple<VariableDeclaration const*, u256, unsigned>> stateVariables() const; private: + static void addNonConflictingAddressMembers(MemberList::MemberMap& _members); + ContractDefinition const& m_contract; /// If true, it is the "super" type of the current contract, i.e. it contains only inherited /// members. diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 25886844..080be359 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -487,6 +487,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArray( // TODO if this is not a byte array, we might just copy byte-by-byte anyway, // because the encoding is position-independent, but we have to check that. Whiskers templ(R"( + // <readableTypeNameFrom> -> <readableTypeNameTo> function <functionName>(start, length, pos) -> end { <storeLength> // might update pos <copyFun>(start, pos, length) @@ -495,6 +496,8 @@ string ABIFunctions::abiEncodingFunctionCalldataArray( )"); templ("storeLength", _to.isDynamicallySized() ? "mstore(pos, length) pos := add(pos, 0x20)" : ""); templ("functionName", functionName); + templ("readableTypeNameFrom", _from.toString(true)); + templ("readableTypeNameTo", _to.toString(true)); templ("copyFun", copyToMemoryFunction(true)); templ("roundUpFun", roundUpFunction()); return templ.render(); @@ -527,6 +530,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( Whiskers templ( dynamicBase ? R"( + // <readableTypeNameFrom> -> <readableTypeNameTo> function <functionName>(value, pos) <return> { let length := <lengthFun>(value) <storeLength> // might update pos @@ -545,6 +549,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( } )" : R"( + // <readableTypeNameFrom> -> <readableTypeNameTo> function <functionName>(value, pos) <return> { let length := <lengthFun>(value) <storeLength> // might update pos @@ -560,6 +565,8 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( )" ); templ("functionName", functionName); + templ("readableTypeNameFrom", _from.toString(true)); + templ("readableTypeNameTo", _to.toString(true)); templ("return", dynamic ? " -> end " : ""); templ("assignEnd", dynamic ? "end := pos" : ""); templ("lengthFun", arrayLengthFunction(_from)); @@ -639,6 +646,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( { solAssert(_to.isByteArray(), ""); Whiskers templ(R"( + // <readableTypeNameFrom> -> <readableTypeNameTo> function <functionName>(value, pos) -> ret { let slotValue := sload(value) switch and(slotValue, 1) @@ -665,6 +673,8 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( } )"); templ("functionName", functionName); + templ("readableTypeNameFrom", _from.toString(true)); + templ("readableTypeNameTo", _to.toString(true)); templ("arrayDataSlot", arrayDataAreaFunction(_from)); return templ.render(); } @@ -681,6 +691,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( // more than desired, i.e. it writes beyond the end of memory. Whiskers templ( R"( + // <readableTypeNameFrom> -> <readableTypeNameTo> function <functionName>(value, pos) <return> { let length := <lengthFun>(value) <storeLength> // might update pos @@ -701,6 +712,8 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( )" ); templ("functionName", functionName); + templ("readableTypeNameFrom", _from.toString(true)); + templ("readableTypeNameTo", _to.toString(true)); templ("return", dynamic ? " -> end " : ""); templ("assignEnd", dynamic ? "end := pos" : ""); templ("lengthFun", arrayLengthFunction(_from)); @@ -748,6 +761,7 @@ string ABIFunctions::abiEncodingFunctionStruct( bool fromStorage = _from.location() == DataLocation::Storage; bool dynamic = _to.isDynamicallyEncoded(); Whiskers templ(R"( + // <readableTypeNameFrom> -> <readableTypeNameTo> function <functionName>(value, pos) <return> { let tail := add(pos, <headSize>) <init> @@ -761,6 +775,8 @@ string ABIFunctions::abiEncodingFunctionStruct( } )"); templ("functionName", functionName); + templ("readableTypeNameFrom", _from.toString(true)); + templ("readableTypeNameTo", _to.toString(true)); templ("return", dynamic ? " -> end " : ""); templ("assignEnd", dynamic ? "end := tail" : ""); // to avoid multiple loads from the same slot for subsequent members @@ -991,9 +1007,11 @@ string ABIFunctions::shiftLeftFunction(size_t _numBits) return createFunction(functionName, [&]() { solAssert(_numBits < 256, ""); return - Whiskers(R"(function <functionName>(value) -> newValue { + Whiskers(R"( + function <functionName>(value) -> newValue { newValue := mul(value, <multiplier>) - })") + } + )") ("functionName", functionName) ("multiplier", toCompactHexWithPrefix(u256(1) << _numBits)) .render(); @@ -1006,9 +1024,11 @@ string ABIFunctions::shiftRightFunction(size_t _numBits, bool _signed) return createFunction(functionName, [&]() { solAssert(_numBits < 256, ""); return - Whiskers(R"(function <functionName>(value) -> newValue { + Whiskers(R"( + function <functionName>(value) -> newValue { newValue := <div>(value, <multiplier>) - })") + } + )") ("functionName", functionName) ("div", _signed ? "sdiv" : "div") ("multiplier", toCompactHexWithPrefix(u256(1) << _numBits)) @@ -1021,9 +1041,11 @@ string ABIFunctions::roundUpFunction() string functionName = "round_up_to_mul_of_32"; return createFunction(functionName, [&]() { return - Whiskers(R"(function <functionName>(value) -> result { + Whiskers(R"( + function <functionName>(value) -> result { result := and(add(value, 31), not(31)) - })") + } + )") ("functionName", functionName) .render(); }); diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index e17188c2..ce8cbb5f 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -291,8 +291,11 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord CompilerUtils utils(m_context); unsigned baseSize = 1; if (!_sourceType.isByteArray()) + { // We always pad the elements, regardless of _padToWordBoundaries. baseSize = _sourceType.baseType()->calldataEncodedSize(); + solAssert(baseSize >= 0x20, ""); + } if (_sourceType.location() == DataLocation::CallData) { diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index d87c7be5..ce9c3b7f 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -38,6 +38,13 @@ #include <utility> #include <numeric> +// Change to "define" to output all intermediate code +#undef SOL_OUTPUT_ASM +#ifdef SOL_OUTPUT_ASM +#include <libsolidity/inlineasm/AsmPrinter.h> +#endif + + using namespace std; namespace dev @@ -313,10 +320,17 @@ void CompilerContext::appendInlineAssembly( ErrorReporter errorReporter(errors); auto scanner = make_shared<Scanner>(CharStream(_assembly), "--CODEGEN--"); auto parserResult = assembly::Parser(errorReporter).parse(scanner); - if (!parserResult || !errorReporter.errors().empty()) +#ifdef SOL_OUTPUT_ASM + cout << assembly::AsmPrinter()(*parserResult) << endl; +#endif + assembly::AsmAnalysisInfo analysisInfo; + bool analyzerResult = false; + if (parserResult) + analyzerResult = assembly::AsmAnalyzer(analysisInfo, errorReporter, false, identifierAccess.resolve).analyze(*parserResult); + if (!parserResult || !errorReporter.errors().empty() || !analyzerResult) { string message = - "Error parsing inline assembly block:\n" + "Error parsing/analyzing inline assembly block:\n" "------------------ Input: -----------------\n" + _assembly + "\n" "------------------ Errors: ----------------\n"; @@ -331,9 +345,6 @@ void CompilerContext::appendInlineAssembly( solAssert(false, message); } - assembly::AsmAnalysisInfo analysisInfo; - assembly::AsmAnalyzer analyzer(analysisInfo, errorReporter, false, identifierAccess.resolve); - solAssert(analyzer.analyze(*parserResult), "Failed to analyze inline assembly block."); solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block."); assembly::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system); } diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index c2bf0f5c..fe37baac 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1714,6 +1714,9 @@ void ExpressionCompiler::appendExternalFunctionCall( if (_functionType.gasSet()) m_context << dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); + else if (m_context.experimentalFeatureActive(ExperimentalFeature::V050)) + // Send all gas (requires tangerine whistle EVM) + m_context << Instruction::GAS; else { // send all gas except the amount needed to execute "SUB" and "CALL" diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp index 522928f0..0ceed3a7 100644 --- a/libsolidity/formal/Z3Interface.cpp +++ b/libsolidity/formal/Z3Interface.cpp @@ -72,28 +72,21 @@ void Z3Interface::addAssertion(Expression const& _expr) pair<CheckResult, vector<string>> Z3Interface::check(vector<Expression> const& _expressionsToEvaluate) { -// cout << "---------------------------------" << endl; -// cout << m_solver << endl; CheckResult result; switch (m_solver.check()) { case z3::check_result::sat: result = CheckResult::SATISFIABLE; - cout << "sat" << endl; break; case z3::check_result::unsat: result = CheckResult::UNSATISFIABLE; - cout << "unsat" << endl; break; case z3::check_result::unknown: result = CheckResult::UNKNOWN; - cout << "unknown" << endl; break; default: solAssert(false, ""); } -// cout << "---------------------------------" << endl; - vector<string> values; if (result != CheckResult::UNSATISFIABLE) @@ -142,7 +135,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr) return m_context.int_val(n.c_str()); } - assert(arity.count(n) && arity.at(n) == arguments.size()); + solAssert(arity.count(n) && arity.at(n) == arguments.size(), ""); if (n == "ite") return z3::ite(arguments[0], arguments[1], arguments[2]); else if (n == "not") diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 3087ad86..1f4df75b 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -256,7 +256,7 @@ std::map<string, dev::solidity::Instruction> const& Parser::instructions() { if ( instruction.second == solidity::Instruction::JUMPDEST || - (solidity::Instruction::PUSH1 <= instruction.second && instruction.second <= solidity::Instruction::PUSH32) + solidity::isPushInstruction(instruction.second) ) continue; string name = instruction.first; @@ -443,9 +443,9 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction) ret.location = ret.instruction.location; solidity::Instruction instr = ret.instruction.instruction; InstructionInfo instrInfo = instructionInfo(instr); - if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16) + if (solidity::isDupInstruction(instr)) fatalParserError("DUPi instructions not allowed for functional notation"); - if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16) + if (solidity::isSwapInstruction(instr)) fatalParserError("SWAPi instructions not allowed for functional notation"); expectToken(Token::LParen); unsigned args = unsigned(instrInfo.args); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 51544f8a..b99fe4ee 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -252,6 +252,14 @@ bool CompilerStack::parseAndAnalyze() return parse() && analyze(); } +bool CompilerStack::isRequestedContract(ContractDefinition const& _contract) const +{ + return + m_requestedContractNames.empty() || + m_requestedContractNames.count(_contract.fullyQualifiedName()) || + m_requestedContractNames.count(_contract.name()); +} + bool CompilerStack::compile() { if (m_stackState < AnalysisSuccessful) @@ -262,7 +270,8 @@ bool CompilerStack::compile() for (Source const* source: m_sourceOrder) for (ASTPointer<ASTNode> const& node: source->ast->nodes()) if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) - compileContract(*contract, compiledContracts); + if (isRequestedContract(*contract)) + compileContract(*contract, compiledContracts); this->link(); m_stackState = CompilationSuccessful; return true; diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index f1bbae47..c567ac2c 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -116,6 +116,13 @@ public: m_optimizeRuns = _runs; } + /// Sets the list of requested contract names. If empty, no filtering is performed and every contract + /// found in the supplied sources is compiled. Names are cleared iff @a _contractNames is missing. + void setRequestedContractNames(std::set<std::string> const& _contractNames = std::set<std::string>{}) + { + m_requestedContractNames = _contractNames; + } + /// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata. void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; } @@ -259,6 +266,9 @@ private: /// Helper function to return path converted strings. std::string sanitizePath(std::string const& _path) const { return boost::filesystem::path(_path).generic_string(); } + /// @returns true if the contract is requested to be compiled. + bool isRequestedContract(ContractDefinition const& _contract) const; + /// Compile a single contract and put the result in @a _compiledContracts. void compileContract( ContractDefinition const& _contract, @@ -297,6 +307,7 @@ private: ReadCallback::Callback m_smtQuery; bool m_optimize = false; unsigned m_optimizeRuns = 200; + std::set<std::string> m_requestedContractNames; std::map<std::string, h160> m_libraries; /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum /// "context:prefix=target" diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index 852b392c..22cc0266 100644 --- a/libsolidity/interface/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -48,7 +48,7 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio ControlFlowGraph cfg(_items); for (BasicBlock const& block: cfg.optimisedBlocks()) { - assertThrow(!!block.startState, OptimizerException, ""); + solAssert(!!block.startState, ""); GasMeter meter(block.startState->copy()); auto const end = _items.begin() + block.end; for (auto iter = _items.begin() + block.begin; iter != end; ++iter) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index b4fbbef9..430739ac 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -92,6 +92,22 @@ Json::Value formatErrorWithException( return formatError(_warning, _type, _component, message, formattedMessage, location); } +set<string> requestedContractNames(Json::Value const& _outputSelection) +{ + set<string> names; + for (auto const& sourceName: _outputSelection.getMemberNames()) + { + for (auto const& contractName: _outputSelection[sourceName].getMemberNames()) + { + /// Consider the "all sources" shortcuts as requesting everything. + if (contractName == "*" || contractName == "") + return set<string>(); + names.insert((sourceName == "*" ? "" : sourceName) + ":" + contractName); + } + } + return names; +} + /// Returns true iff @a _hash (hex with 0x prefix) is the Keccak256 hash of the binary data in @a _content. bool hashMatchesContent(string const& _hash, string const& _content) { @@ -265,6 +281,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) Json::Value metadataSettings = settings.get("metadata", Json::Value()); m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool()); + Json::Value outputSelection = settings.get("outputSelection", Json::Value()); + m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection)); + auto scannerFromSourceName = [&](string const& _sourceName) -> solidity::Scanner const& { return m_compilerStack.scanner(_sourceName); }; try diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 9a8bb358..821e81d2 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1133,6 +1133,7 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme options.allowVar = true; options.allowLocationSpecifier = true; variables.push_back(parseVariableDeclaration(options, _lookAheadArrayType)); + nodeFactory.setEndPositionFromNode(variables.back()); } if (m_scanner->currentToken() == Token::Assign) { |