mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Control flow for try statements.
This commit is contained in:
parent
644a402166
commit
b5bc52f2a7
@ -85,6 +85,18 @@ bool ControlFlowBuilder::visit(Conditional const& _conditional)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ControlFlowBuilder::visit(TryStatement const& _tryStatement)
|
||||||
|
{
|
||||||
|
appendControlFlow(_tryStatement.externalCall());
|
||||||
|
|
||||||
|
auto nodes = splitFlow(_tryStatement.clauses().size());
|
||||||
|
for (size_t i = 0; i < _tryStatement.clauses().size(); ++i)
|
||||||
|
nodes[i] = createFlow(nodes[i], _tryStatement.clauses()[i]->block());
|
||||||
|
mergeFlow(nodes);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ControlFlowBuilder::visit(IfStatement const& _ifStatement)
|
bool ControlFlowBuilder::visit(IfStatement const& _ifStatement)
|
||||||
{
|
{
|
||||||
solAssert(!!m_currentNode, "");
|
solAssert(!!m_currentNode, "");
|
||||||
|
@ -45,6 +45,7 @@ private:
|
|||||||
// Visits for constructing the control flow.
|
// Visits for constructing the control flow.
|
||||||
bool visit(BinaryOperation const& _operation) override;
|
bool visit(BinaryOperation const& _operation) override;
|
||||||
bool visit(Conditional const& _conditional) override;
|
bool visit(Conditional const& _conditional) override;
|
||||||
|
bool visit(TryStatement const& _tryStatement) override;
|
||||||
bool visit(IfStatement const& _ifStatement) override;
|
bool visit(IfStatement const& _ifStatement) override;
|
||||||
bool visit(ForStatement const& _forStatement) override;
|
bool visit(ForStatement const& _forStatement) override;
|
||||||
bool visit(WhileStatement const& _whileStatement) override;
|
bool visit(WhileStatement const& _whileStatement) override;
|
||||||
@ -98,12 +99,27 @@ private:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Splits the control flow starting at the current node into @a _n paths.
|
||||||
|
/// m_currentNode is set to nullptr and has to be set manually or
|
||||||
|
/// using mergeFlow later.
|
||||||
|
std::vector<CFGNode*> splitFlow(size_t n)
|
||||||
|
{
|
||||||
|
std::vector<CFGNode*> result(n);
|
||||||
|
for (auto& node: result)
|
||||||
|
{
|
||||||
|
node = m_nodeContainer.newNode();
|
||||||
|
connect(m_currentNode, node);
|
||||||
|
}
|
||||||
|
m_currentNode = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// Merges the control flow of @a _nodes to @a _endNode.
|
/// Merges the control flow of @a _nodes to @a _endNode.
|
||||||
/// If @a _endNode is nullptr, a new node is creates and used as end node.
|
/// If @a _endNode is nullptr, a new node is creates and used as end node.
|
||||||
/// Sets the merge destination as current node.
|
/// Sets the merge destination as current node.
|
||||||
/// Note: @a _endNode may be one of the nodes in @a _nodes.
|
/// Note: @a _endNode may be one of the nodes in @a _nodes.
|
||||||
template<size_t n>
|
template<typename C>
|
||||||
void mergeFlow(std::array<CFGNode*, n> const& _nodes, CFGNode* _endNode = nullptr)
|
void mergeFlow(C const& _nodes, CFGNode* _endNode = nullptr)
|
||||||
{
|
{
|
||||||
CFGNode* mergeDestination = (_endNode == nullptr) ? m_nodeContainer.newNode() : _endNode;
|
CFGNode* mergeDestination = (_endNode == nullptr) ? m_nodeContainer.newNode() : _endNode;
|
||||||
for (auto& node: _nodes)
|
for (auto& node: _nodes)
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
contract C {
|
||||||
|
struct S { bool f; }
|
||||||
|
S s;
|
||||||
|
function ext() external {}
|
||||||
|
function f() internal returns (S storage r)
|
||||||
|
{
|
||||||
|
try this.ext() { }
|
||||||
|
catch (bytes memory) { r = s; }
|
||||||
|
}
|
||||||
|
function g() internal returns (S storage r)
|
||||||
|
{
|
||||||
|
try this.ext() { r = s; }
|
||||||
|
catch (bytes memory) { }
|
||||||
|
}
|
||||||
|
function h() internal returns (S storage r)
|
||||||
|
{
|
||||||
|
try this.ext() {}
|
||||||
|
catch Error (string memory) { r = s; }
|
||||||
|
catch (bytes memory) { r = s; }
|
||||||
|
}
|
||||||
|
function i() internal returns (S storage r)
|
||||||
|
{
|
||||||
|
try this.ext() { r = s; }
|
||||||
|
catch (bytes memory) { return r; }
|
||||||
|
r = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=byzantium
|
||||||
|
// ----
|
||||||
|
// TypeError: (113-124): This variable is of storage pointer type and can be returned without prior assignment.
|
||||||
|
// TypeError: (240-251): This variable is of storage pointer type and can be returned without prior assignment.
|
||||||
|
// TypeError: (367-378): This variable is of storage pointer type and can be returned without prior assignment.
|
||||||
|
// TypeError: (631-632): This variable is of storage pointer type and can be accessed without prior assignment.
|
@ -0,0 +1,24 @@
|
|||||||
|
contract C {
|
||||||
|
struct S { bool f; }
|
||||||
|
S s;
|
||||||
|
function ext() external { }
|
||||||
|
function f() internal returns (S storage r)
|
||||||
|
{
|
||||||
|
try this.ext() { r = s; }
|
||||||
|
catch (bytes memory) { r = s; }
|
||||||
|
}
|
||||||
|
function g() internal returns (S storage r)
|
||||||
|
{
|
||||||
|
try this.ext() { r = s; }
|
||||||
|
catch Error (string memory) { r = s; }
|
||||||
|
catch (bytes memory) { r = s; }
|
||||||
|
}
|
||||||
|
function h() internal returns (S storage r)
|
||||||
|
{
|
||||||
|
try this.ext() { }
|
||||||
|
catch (bytes memory) { }
|
||||||
|
r = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=byzantium
|
Loading…
Reference in New Issue
Block a user