Assertions that throw InternalCompilerErrors.

This commit is contained in:
Christian 2014-12-17 16:23:18 +01:00
parent 3d98ec1323
commit 5a1a83ff42
11 changed files with 105 additions and 84 deletions

View File

@ -21,7 +21,7 @@
*/
#include <algorithm>
#include <libsolidity/Utils.h>
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/Exceptions.h>
@ -145,8 +145,7 @@ void Return::checkTypeRequirements()
{
if (!m_expression)
return;
if (asserts(m_returnParameters))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Return parameters not assigned."));
solAssert(m_returnParameters, "Return parameters not assigned.");
if (m_returnParameters->getParameters().size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
"than in returns declaration."));
@ -336,8 +335,7 @@ void IndexAccess::checkTypeRequirements()
void Identifier::checkTypeRequirements()
{
if (asserts(m_referencedDeclaration))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier not resolved."));
solAssert(m_referencedDeclaration, "Identifier not resolved.");
VariableDeclaration const* variable = dynamic_cast<VariableDeclaration const*>(m_referencedDeclaration);
if (variable)

16
AST.h
View File

@ -27,6 +27,7 @@
#include <vector>
#include <memory>
#include <boost/noncopyable.hpp>
#include <libsolidity/Utils.h>
#include <libsolidity/ASTForward.h>
#include <libsolidity/BaseTypes.h>
#include <libsolidity/Token.h>
@ -364,7 +365,7 @@ public:
explicit ElementaryTypeName(Location const& _location, Token::Value _type):
TypeName(_location), m_type(_type)
{
if (asserts(Token::isElementaryTypeName(_type))) BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(Token::isElementaryTypeName(_type), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
@ -575,8 +576,7 @@ public:
void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; }
ParameterList const& getFunctionReturnParameters() const
{
if (asserts(m_returnParameters))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(m_returnParameters, "");
return *m_returnParameters;
}
Expression const* getExpression() const { return m_expression.get(); }
@ -682,7 +682,7 @@ public:
Expression(_location), m_leftHandSide(_leftHandSide),
m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide)
{
if (asserts(Token::isAssignmentOp(_assignmentOperator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(Token::isAssignmentOp(_assignmentOperator), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
@ -710,7 +710,7 @@ public:
Expression(_location), m_operator(_operator),
m_subExpression(_subExpression), m_isPrefix(_isPrefix)
{
if (asserts(Token::isUnaryOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(Token::isUnaryOp(_operator), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
@ -737,7 +737,7 @@ public:
Token::Value _operator, ASTPointer<Expression> const& _right):
Expression(_location), m_left(_left), m_operator(_operator), m_right(_right)
{
if (asserts(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
@ -799,7 +799,7 @@ public:
std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
/// Returns the referenced contract. Can only be called after type checking.
ContractDefinition const* getContract() const { if (asserts(m_contract)) BOOST_THROW_EXCEPTION(InternalCompilerError()); else return m_contract; }
ContractDefinition const* getContract() const { solAssert(m_contract, ""); return m_contract; }
private:
ASTPointer<Identifier> m_contractName;
@ -894,7 +894,7 @@ public:
ElementaryTypeNameExpression(Location const& _location, Token::Value _typeToken):
PrimaryExpression(_location), m_typeToken(_typeToken)
{
if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(Token::isElementaryTypeName(_typeToken), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;

View File

@ -27,8 +27,10 @@
using namespace std;
namespace dev {
namespace solidity {
namespace dev
{
namespace solidity
{
void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaration)
{
@ -65,8 +67,7 @@ void CompilerContext::addFunction(FunctionDefinition const& _function)
bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
{
auto ret = m_compiledContracts.find(&_contract);
if (asserts(ret != m_compiledContracts.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Compiled contract not found."));
solAssert(ret != m_compiledContracts.end(), "Compiled contract not found.");
return *ret->second;
}
@ -78,16 +79,14 @@ bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const
{
auto res = m_functionEntryLabels.find(&_function);
if (asserts(res != m_functionEntryLabels.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function entry label not found."));
solAssert(res != m_functionEntryLabels.end(), "Function entry label not found.");
return res->second.tag();
}
unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const
{
auto res = m_localVariables.find(&_declaration);
if (asserts(res != m_localVariables.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack."));
solAssert(res != m_localVariables.end(), "Variable not found on stack.");
return m_localVariablesSize - res->second - 1;
}
@ -99,12 +98,9 @@ unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const
{
auto it = m_stateVariables.find(&_declaration);
if (it == m_stateVariables.end())
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found in storage."));
solAssert(it != m_stateVariables.end(), "Variable not found in storage.");
return it->second;
}
}
}

View File

@ -39,8 +39,7 @@ void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _left
return;
}
eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD;
if (asserts(_bytes <= 32))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory load of more than 32 bytes requested."));
solAssert(_bytes <= 32, "Memory load of more than 32 bytes requested.");
if (_bytes == 32)
m_context << u256(_offset) << load;
else
@ -63,8 +62,7 @@ void CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftA
m_context << eth::Instruction::POP;
return;
}
if (asserts(_bytes <= 32))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory store of more than 32 bytes requested."));
solAssert(_bytes <= 32, "Memory store of more than 32 bytes requested.");
if (_bytes != 32 && !_leftAligned)
// shift the value accordingly before storing
m_context << (u256(1) << ((32 - _bytes) * 8)) << eth::Instruction::MUL;

View File

@ -30,8 +30,10 @@
using namespace std;
namespace dev {
namespace solidity {
namespace dev
{
namespace solidity
{
void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression const& _expression, bool _optimize)
{
@ -51,8 +53,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
_assignment.getRightHandSide().accept(*this);
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
_assignment.getLeftHandSide().accept(*this);
if (asserts(m_currentLValue.isValid()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not retrieved."));
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
Token::Value op = _assignment.getAssignmentOperator();
if (op != Token::ASSIGN) // compound assignment
@ -84,8 +85,7 @@ void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation)
break;
case Token::DELETE: // delete
// @todo semantics change for complex types
if (asserts(m_currentLValue.isValid()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not retrieved."));
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
m_context << u256(0);
if (m_currentLValue.storesReferenceOnStack())
@ -95,8 +95,7 @@ void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation)
break;
case Token::INC: // ++ (pre- or postfix)
case Token::DEC: // -- (pre- or postfix)
if (asserts(m_currentLValue.isValid()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not retrieved."));
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
m_currentLValue.retrieveValue(_unaryOperation);
if (!_unaryOperation.isPrefixOperation())
{
@ -179,8 +178,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
if (_functionCall.isTypeConversion())
{
//@todo struct construction
if (asserts(_functionCall.getArguments().size() == 1))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(_functionCall.getArguments().size() == 1, "");
Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this);
if (firstArgument.getType()->getCategory() == Type::Category::CONTRACT &&
@ -195,8 +193,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments();
if (asserts(arguments.size() == function.getParameterTypes().size()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(arguments.size() == function.getParameterTypes().size(), "");
switch (function.getLocation())
{
@ -282,12 +279,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
bool ExpressionCompiler::visit(NewExpression const& _newExpression)
{
ContractType const* type = dynamic_cast<ContractType const*>(_newExpression.getType().get());
if (asserts(type))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(type, "");
TypePointers const& types = type->getConstructorType()->getParameterTypes();
vector<ASTPointer<Expression const>> arguments = _newExpression.getArguments();
if (asserts(arguments.size() == types.size()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(arguments.size() == types.size(), "");
// copy the contracts code into memory
bytes const& bytecode = m_context.getCompiledContract(*_newExpression.getContract());
@ -439,8 +434,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation)
{
Token::Value const op = _binaryOperation.getOperator();
if (asserts(op == Token::OR || op == Token::AND))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(op == Token::OR || op == Token::AND, "");
_binaryOperation.getLeftExpression().accept(*this);
m_context << eth::Instruction::DUP1;
@ -592,8 +586,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
vector<ASTPointer<Expression const>> const& _arguments,
FunctionCallOptions const& _options)
{
if (asserts(_arguments.size() == _functionType.getParameterTypes().size()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(_arguments.size() == _functionType.getParameterTypes().size(), "");
unsigned dataOffset = _options.bare ? 0 : 1; // reserve one byte for the function index
for (unsigned i = 0; i < _arguments.size(); ++i)

View File

@ -198,8 +198,7 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con
std::string::const_iterator _end)
{
// Should never be called with an empty vector
if (asserts(!m_params.empty()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Tried to append to empty parameter"));
solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter");
auto pair = m_params.back();
pair.second += " ";

View File

@ -70,8 +70,7 @@ void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract)
void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
{
m_scopes[nullptr].registerDeclaration(_declaration, true);
if (asserts(_declaration.getScope() == nullptr))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Updated declaration outside global scope."));
solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope.");
}
Declaration const* NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
@ -133,8 +132,7 @@ void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefini
{
// Register the local variables with the function
// This does not fit here perfectly, but it saves us another AST visit.
if (asserts(m_currentFunction))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable definition without function."));
solAssert(m_currentFunction, "Variable definition without function.");
m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration());
}
@ -149,15 +147,13 @@ void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declara
map<ASTNode const*, DeclarationContainer>::iterator iter;
bool newlyAdded;
tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope]));
if (asserts(newlyAdded))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to add new scope."));
solAssert(newlyAdded, "Unable to add new scope.");
m_currentScope = &_declaration;
}
void DeclarationRegistrationHelper::closeCurrentScope()
{
if (asserts(m_currentScope))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Closed non-existing scope."));
solAssert(m_currentScope, "Closed non-existing scope.");
m_currentScope = m_scopes[m_currentScope].getEnclosingDeclaration();
}
@ -196,8 +192,7 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable)
bool ReferencesResolver::visit(Return& _return)
{
if (asserts(m_returnParameters))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Return parameters not set."));
solAssert(m_returnParameters, "Return parameters not set.");
_return.setFunctionReturnParameters(*m_returnParameters);
return true;
}

View File

@ -52,6 +52,7 @@
#include <algorithm>
#include <tuple>
#include <libsolidity/Utils.h>
#include <libsolidity/Scanner.h>
using namespace std;
@ -249,8 +250,7 @@ Token::Value Scanner::scanDocumentationComment()
Token::Value Scanner::skipMultiLineComment()
{
if (asserts(m_char == '*'))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(m_char == '*', "");
advance();
while (!isSourcePastEndOfInput())
{
@ -597,8 +597,7 @@ Token::Value Scanner::scanNumber(char _charSeen)
// scan exponent, if any
if (m_char == 'e' || m_char == 'E')
{
if (asserts(kind != HEX)) // 'e'/'E' must be scanned as part of the hex number
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(kind != HEX, "'e'/'E' must be scanned as part of the hex number");
if (kind != DECIMAL)
return Token::ILLEGAL;
// scan exponent
@ -639,8 +638,7 @@ static Token::Value keywordOrIdentifierToken(string const& _input)
Token::Value Scanner::scanIdentifierOrKeyword()
{
if (asserts(isIdentifierStart(m_char)))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(isIdentifierStart(m_char), "");
LiteralScope literal(this, LITERAL_TYPE_STRING);
addLiteralCharAndAdvance();
// Scan the rest of the identifier characters.
@ -662,8 +660,7 @@ char CharStream::advanceAndGet(size_t _chars)
char CharStream::rollback(size_t _amount)
{
if (asserts(m_pos >= _amount))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(m_pos >= _amount, "");
m_pos -= _amount;
return get();
}

13
Token.h
View File

@ -44,6 +44,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libsolidity/Utils.h>
#include <libsolidity/Exceptions.h>
namespace dev
@ -344,8 +345,7 @@ public:
// (e.g. "LT" for the token LT).
static char const* getName(Value tok)
{
if (asserts(tok < NUM_TOKENS))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(tok < NUM_TOKENS, "");
return m_name[tok];
}
@ -360,8 +360,7 @@ public:
static Value AssignmentToBinaryOp(Value op)
{
if (asserts(isAssignmentOp(op) && op != ASSIGN))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(isAssignmentOp(op) && op != ASSIGN, "");
return Token::Value(op + (BIT_OR - ASSIGN_BIT_OR));
}
@ -375,8 +374,7 @@ public:
// have a (unique) string (e.g. an IDENTIFIER).
static char const* toString(Value tok)
{
if (asserts(tok < NUM_TOKENS))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(tok < NUM_TOKENS, "");
return m_string[tok];
}
@ -384,8 +382,7 @@ public:
// operators; returns 0 otherwise.
static int precedence(Value tok)
{
if (asserts(tok < NUM_TOKENS))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(tok < NUM_TOKENS, "");
return m_precedence[tok];
}

View File

@ -22,6 +22,7 @@
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libsolidity/Utils.h>
#include <libsolidity/Types.h>
#include <libsolidity/AST.h>
@ -34,8 +35,7 @@ namespace solidity
shared_ptr<Type const> Type::fromElementaryTypeName(Token::Value _typeToken)
{
if (asserts(Token::isElementaryTypeName(_typeToken)))
BOOST_THROW_EXCEPTION(InternalCompilerError());
solAssert(Token::isElementaryTypeName(_typeToken), "");
if (Token::INT <= _typeToken && _typeToken <= Token::HASH256)
{
@ -120,8 +120,8 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
{
if (isAddress())
m_bits = 160;
if (asserts(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid bit number for integer type: " + dev::toString(_bits)));
solAssert(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
"Invalid bit number for integer type: " + dev::toString(_bits));
}
bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
@ -215,9 +215,8 @@ shared_ptr<StaticStringType> StaticStringType::smallestTypeForLiteral(string con
StaticStringType::StaticStringType(int _bytes): m_bytes(_bytes)
{
if (asserts(m_bytes >= 0 && m_bytes <= 32))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid byte number for static string type: " +
dev::toString(m_bytes)));
solAssert(m_bytes >= 0 && m_bytes <= 32,
"Invalid byte number for static string type: " + dev::toString(m_bytes));
}
bool StaticStringType::isImplicitlyConvertibleTo(Type const& _convertTo) const

49
Utils.h Normal file
View File

@ -0,0 +1,49 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity Utilities.
*/
#pragma once
#include <string>
#include <libsolidity/Exceptions.h>
namespace dev
{
namespace solidity
{
/// Assertion that throws an InternalCompilerError containing the given description if it is not met.
#define solAssert(CONDITION, DESCRIPTION) \
::dev::solidity::solAssertAux(CONDITION, DESCRIPTION, __LINE__, __FILE__, ETH_FUNC)
inline void solAssertAux(bool _condition, std::string const& _errorDescription, unsigned _line,
char const* _file, char const* _function)
{
if (!_condition)
::boost::throw_exception( InternalCompilerError()
<< errinfo_comment(_errorDescription)
<< ::boost::throw_function(_function)
<< ::boost::throw_file(_file)
<< ::boost::throw_line(_line));
}
}
}