mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9118 from ethereum/develop
Merge develop into breaking.
This commit is contained in:
commit
259292c884
@ -44,6 +44,7 @@ Bugfixes:
|
|||||||
* Type Checker: Fix internal compiler error when trying to decode too large static arrays.
|
* Type Checker: Fix internal compiler error when trying to decode too large static arrays.
|
||||||
* Type Checker: Fix wrong compiler error when referencing an overridden function without calling it.
|
* Type Checker: Fix wrong compiler error when referencing an overridden function without calling it.
|
||||||
* Type Checker: Fix internal compiler error when forward referencing non-literal constants from inline assembly.
|
* Type Checker: Fix internal compiler error when forward referencing non-literal constants from inline assembly.
|
||||||
|
* Type Checker: Disallow usage of override with non-public state variables.
|
||||||
* NatSpec: DocString block is terminated when encountering an empty line.
|
* NatSpec: DocString block is terminated when encountering an empty line.
|
||||||
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
|
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
|
||||||
* Code Generator: Trigger proper unimplemented errors on certain array copy operations.
|
* Code Generator: Trigger proper unimplemented errors on certain array copy operations.
|
||||||
|
@ -41,7 +41,7 @@ using namespace solidity::util;
|
|||||||
AssemblyItem const& Assembly::append(AssemblyItem const& _i)
|
AssemblyItem const& Assembly::append(AssemblyItem const& _i)
|
||||||
{
|
{
|
||||||
assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow.");
|
assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow.");
|
||||||
m_deposit += _i.deposit();
|
m_deposit += static_cast<int>(_i.deposit());
|
||||||
m_items.emplace_back(_i);
|
m_items.emplace_back(_i);
|
||||||
if (!m_items.back().location().isValid() && m_currentSourceLocation.isValid())
|
if (!m_items.back().location().isValid() && m_currentSourceLocation.isValid())
|
||||||
m_items.back().setLocation(m_currentSourceLocation);
|
m_items.back().setLocation(m_currentSourceLocation);
|
||||||
@ -77,10 +77,10 @@ string locationFromSources(StringMap const& _sourceCodes, SourceLocation const&
|
|||||||
return "";
|
return "";
|
||||||
|
|
||||||
string const& source = it->second;
|
string const& source = it->second;
|
||||||
if (size_t(_location.start) >= source.size())
|
if (static_cast<size_t>(_location.start) >= source.size())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
string cut = source.substr(_location.start, _location.end - _location.start);
|
string cut = source.substr(static_cast<size_t>(_location.start), static_cast<size_t>(_location.end - _location.start));
|
||||||
auto newLinePos = cut.find_first_of("\n");
|
auto newLinePos = cut.find_first_of("\n");
|
||||||
if (newLinePos != string::npos)
|
if (newLinePos != string::npos)
|
||||||
cut = cut.substr(0, newLinePos) + "...";
|
cut = cut.substr(0, newLinePos) + "...";
|
||||||
@ -106,7 +106,7 @@ public:
|
|||||||
if (!(
|
if (!(
|
||||||
_item.canBeFunctional() &&
|
_item.canBeFunctional() &&
|
||||||
_item.returnValues() <= 1 &&
|
_item.returnValues() <= 1 &&
|
||||||
_item.arguments() <= int(m_pending.size())
|
_item.arguments() <= m_pending.size()
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
flush();
|
flush();
|
||||||
@ -117,7 +117,7 @@ public:
|
|||||||
if (_item.arguments() > 0)
|
if (_item.arguments() > 0)
|
||||||
{
|
{
|
||||||
expression += "(";
|
expression += "(";
|
||||||
for (int i = 0; i < _item.arguments(); ++i)
|
for (size_t i = 0; i < _item.arguments(); ++i)
|
||||||
{
|
{
|
||||||
expression += m_pending.back();
|
expression += m_pending.back();
|
||||||
m_pending.pop_back();
|
m_pending.pop_back();
|
||||||
@ -225,12 +225,12 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
|
|||||||
Json::Value& collection = root[".code"] = Json::arrayValue;
|
Json::Value& collection = root[".code"] = Json::arrayValue;
|
||||||
for (AssemblyItem const& i: m_items)
|
for (AssemblyItem const& i: m_items)
|
||||||
{
|
{
|
||||||
unsigned sourceIndex = unsigned(-1);
|
int sourceIndex = -1;
|
||||||
if (i.location().source)
|
if (i.location().source)
|
||||||
{
|
{
|
||||||
auto iter = _sourceIndices.find(i.location().source->name());
|
auto iter = _sourceIndices.find(i.location().source->name());
|
||||||
if (iter != _sourceIndices.end())
|
if (iter != _sourceIndices.end())
|
||||||
sourceIndex = iter->second;
|
sourceIndex = static_cast<int>(iter->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (i.type())
|
switch (i.type())
|
||||||
@ -340,7 +340,7 @@ AssemblyItem Assembly::namedTag(string const& _name)
|
|||||||
{
|
{
|
||||||
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
|
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
|
||||||
if (!m_namedTags.count(_name))
|
if (!m_namedTags.count(_name))
|
||||||
m_namedTags[_name] = size_t(newTag().data());
|
m_namedTags[_name] = static_cast<size_t>(newTag().data());
|
||||||
return AssemblyItem{Tag, m_namedTags.at(_name)};
|
return AssemblyItem{Tag, m_namedTags.at(_name)};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +441,7 @@ map<u256, u256> Assembly::optimiseInternal(
|
|||||||
for (auto const& replacement: deduplicator.replacedTags())
|
for (auto const& replacement: deduplicator.replacedTags())
|
||||||
{
|
{
|
||||||
assertThrow(
|
assertThrow(
|
||||||
replacement.first <= size_t(-1) && replacement.second <= size_t(-1),
|
replacement.first <= numeric_limits<size_t>::max() && replacement.second <= numeric_limits<size_t>::max(),
|
||||||
OptimizerException,
|
OptimizerException,
|
||||||
"Invalid tag replacement."
|
"Invalid tag replacement."
|
||||||
);
|
);
|
||||||
@ -451,8 +451,8 @@ map<u256, u256> Assembly::optimiseInternal(
|
|||||||
"Replacement already known."
|
"Replacement already known."
|
||||||
);
|
);
|
||||||
tagReplacements[replacement.first] = replacement.second;
|
tagReplacements[replacement.first] = replacement.second;
|
||||||
if (_tagsReferencedFromOutside.erase(size_t(replacement.first)))
|
if (_tagsReferencedFromOutside.erase(static_cast<size_t>(replacement.first)))
|
||||||
_tagsReferencedFromOutside.insert(size_t(replacement.second));
|
_tagsReferencedFromOutside.insert(static_cast<size_t>(replacement.second));
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -479,7 +479,7 @@ map<u256, u256> Assembly::optimiseInternal(
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
optimisedChunk = eliminator.getOptimizedItems();
|
optimisedChunk = eliminator.getOptimizedItems();
|
||||||
shouldReplace = (optimisedChunk.size() < size_t(iter - orig));
|
shouldReplace = (optimisedChunk.size() < static_cast<size_t>(iter - orig));
|
||||||
}
|
}
|
||||||
catch (StackTooDeepException const&)
|
catch (StackTooDeepException const&)
|
||||||
{
|
{
|
||||||
@ -544,7 +544,7 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
immutableReferencesBySub = linkerObject.immutableReferences;
|
immutableReferencesBySub = linkerObject.immutableReferences;
|
||||||
}
|
}
|
||||||
for (size_t tagPos: sub->m_tagPositionsInBytecode)
|
for (size_t tagPos: sub->m_tagPositionsInBytecode)
|
||||||
if (tagPos != size_t(-1) && tagPos > subTagSize)
|
if (tagPos != numeric_limits<size_t>::max() && tagPos > subTagSize)
|
||||||
subTagSize = tagPos;
|
subTagSize = tagPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +567,7 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
);
|
);
|
||||||
|
|
||||||
size_t bytesRequiredForCode = bytesRequired(subTagSize);
|
size_t bytesRequiredForCode = bytesRequired(subTagSize);
|
||||||
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, -1);
|
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, numeric_limits<size_t>::max());
|
||||||
map<size_t, pair<size_t, size_t>> tagRef;
|
map<size_t, pair<size_t, size_t>> tagRef;
|
||||||
multimap<h256, unsigned> dataRef;
|
multimap<h256, unsigned> dataRef;
|
||||||
multimap<size_t, size_t> subRef;
|
multimap<size_t, size_t> subRef;
|
||||||
@ -586,7 +586,7 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
for (AssemblyItem const& i: m_items)
|
for (AssemblyItem const& i: m_items)
|
||||||
{
|
{
|
||||||
// store position of the invalid jump destination
|
// store position of the invalid jump destination
|
||||||
if (i.type() != Tag && m_tagPositionsInBytecode[0] == size_t(-1))
|
if (i.type() != Tag && m_tagPositionsInBytecode[0] == numeric_limits<size_t>::max())
|
||||||
m_tagPositionsInBytecode[0] = ret.bytecode.size();
|
m_tagPositionsInBytecode[0] = ret.bytecode.size();
|
||||||
|
|
||||||
switch (i.type())
|
switch (i.type())
|
||||||
@ -629,15 +629,15 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
|
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
|
||||||
break;
|
break;
|
||||||
case PushSub:
|
case PushSub:
|
||||||
assertThrow(i.data() <= size_t(-1), AssemblyException, "");
|
assertThrow(i.data() <= numeric_limits<size_t>::max(), AssemblyException, "");
|
||||||
ret.bytecode.push_back(dataRefPush);
|
ret.bytecode.push_back(dataRefPush);
|
||||||
subRef.insert(make_pair(size_t(i.data()), ret.bytecode.size()));
|
subRef.insert(make_pair(static_cast<size_t>(i.data()), ret.bytecode.size()));
|
||||||
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
|
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
|
||||||
break;
|
break;
|
||||||
case PushSubSize:
|
case PushSubSize:
|
||||||
{
|
{
|
||||||
assertThrow(i.data() <= size_t(-1), AssemblyException, "");
|
assertThrow(i.data() <= numeric_limits<size_t>::max(), AssemblyException, "");
|
||||||
auto s = m_subs.at(size_t(i.data()))->assemble().bytecode.size();
|
auto s = m_subs.at(static_cast<size_t>(i.data()))->assemble().bytecode.size();
|
||||||
i.setPushedValue(u256(s));
|
i.setPushedValue(u256(s));
|
||||||
uint8_t b = max<unsigned>(1, util::bytesRequired(s));
|
uint8_t b = max<unsigned>(1, util::bytesRequired(s));
|
||||||
ret.bytecode.push_back((uint8_t)Instruction::PUSH1 - 1 + b);
|
ret.bytecode.push_back((uint8_t)Instruction::PUSH1 - 1 + b);
|
||||||
@ -683,10 +683,10 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
break;
|
break;
|
||||||
case Tag:
|
case Tag:
|
||||||
assertThrow(i.data() != 0, AssemblyException, "Invalid tag position.");
|
assertThrow(i.data() != 0, AssemblyException, "Invalid tag position.");
|
||||||
assertThrow(i.splitForeignPushTag().first == size_t(-1), AssemblyException, "Foreign tag.");
|
assertThrow(i.splitForeignPushTag().first == numeric_limits<size_t>::max(), AssemblyException, "Foreign tag.");
|
||||||
assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large.");
|
assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large.");
|
||||||
assertThrow(m_tagPositionsInBytecode[size_t(i.data())] == size_t(-1), AssemblyException, "Duplicate tag position.");
|
assertThrow(m_tagPositionsInBytecode[static_cast<size_t>(i.data())] == numeric_limits<size_t>::max(), AssemblyException, "Duplicate tag position.");
|
||||||
m_tagPositionsInBytecode[size_t(i.data())] = ret.bytecode.size();
|
m_tagPositionsInBytecode[static_cast<size_t>(i.data())] = ret.bytecode.size();
|
||||||
ret.bytecode.push_back((uint8_t)Instruction::JUMPDEST);
|
ret.bytecode.push_back((uint8_t)Instruction::JUMPDEST);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -722,14 +722,14 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
size_t subId;
|
size_t subId;
|
||||||
size_t tagId;
|
size_t tagId;
|
||||||
tie(subId, tagId) = i.second;
|
tie(subId, tagId) = i.second;
|
||||||
assertThrow(subId == size_t(-1) || subId < m_subs.size(), AssemblyException, "Invalid sub id");
|
assertThrow(subId == numeric_limits<size_t>::max() || subId < m_subs.size(), AssemblyException, "Invalid sub id");
|
||||||
std::vector<size_t> const& tagPositions =
|
std::vector<size_t> const& tagPositions =
|
||||||
subId == size_t(-1) ?
|
subId == numeric_limits<size_t>::max() ?
|
||||||
m_tagPositionsInBytecode :
|
m_tagPositionsInBytecode :
|
||||||
m_subs[subId]->m_tagPositionsInBytecode;
|
m_subs[subId]->m_tagPositionsInBytecode;
|
||||||
assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag.");
|
assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag.");
|
||||||
size_t pos = tagPositions[tagId];
|
size_t pos = tagPositions[tagId];
|
||||||
assertThrow(pos != size_t(-1), AssemblyException, "Reference to tag without position.");
|
assertThrow(pos != numeric_limits<size_t>::max(), AssemblyException, "Reference to tag without position.");
|
||||||
assertThrow(util::bytesRequired(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space.");
|
assertThrow(util::bytesRequired(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space.");
|
||||||
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
|
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
|
||||||
toBigEndian(pos, r);
|
toBigEndian(pos, r);
|
||||||
|
@ -34,7 +34,7 @@ AssemblyItem AssemblyItem::toSubAssemblyTag(size_t _subId) const
|
|||||||
{
|
{
|
||||||
assertThrow(data() < (u256(1) << 64), util::Exception, "Tag already has subassembly set.");
|
assertThrow(data() < (u256(1) << 64), util::Exception, "Tag already has subassembly set.");
|
||||||
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
||||||
size_t tag = size_t(u256(data()) & 0xffffffffffffffffULL);
|
auto tag = static_cast<size_t>(u256(data()) & 0xffffffffffffffffULL);
|
||||||
AssemblyItem r = *this;
|
AssemblyItem r = *this;
|
||||||
r.m_type = PushTag;
|
r.m_type = PushTag;
|
||||||
r.setPushTagSubIdAndTag(_subId, tag);
|
r.setPushTagSubIdAndTag(_subId, tag);
|
||||||
@ -45,8 +45,8 @@ pair<size_t, size_t> AssemblyItem::splitForeignPushTag() const
|
|||||||
{
|
{
|
||||||
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
||||||
u256 combined = u256(data());
|
u256 combined = u256(data());
|
||||||
size_t subId = size_t((combined >> 64) - 1);
|
size_t subId = static_cast<size_t>((combined >> 64) - 1);
|
||||||
size_t tag = size_t(combined & 0xffffffffffffffffULL);
|
size_t tag = static_cast<size_t>(combined & 0xffffffffffffffffULL);
|
||||||
return make_pair(subId, tag);
|
return make_pair(subId, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
|
|||||||
{
|
{
|
||||||
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
||||||
u256 data = _tag;
|
u256 data = _tag;
|
||||||
if (_subId != size_t(-1))
|
if (_subId != numeric_limits<size_t>::max())
|
||||||
data |= (u256(_subId) + 1) << 64;
|
data |= (u256(_subId) + 1) << 64;
|
||||||
setData(data);
|
setData(data);
|
||||||
}
|
}
|
||||||
@ -93,22 +93,22 @@ unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const
|
|||||||
assertThrow(false, InvalidOpcode, "");
|
assertThrow(false, InvalidOpcode, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
int AssemblyItem::arguments() const
|
size_t AssemblyItem::arguments() const
|
||||||
{
|
{
|
||||||
if (type() == Operation)
|
if (type() == Operation)
|
||||||
return instructionInfo(instruction()).args;
|
return static_cast<size_t>(instructionInfo(instruction()).args);
|
||||||
else if (type() == AssignImmutable)
|
else if (type() == AssignImmutable)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AssemblyItem::returnValues() const
|
size_t AssemblyItem::returnValues() const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case Operation:
|
case Operation:
|
||||||
return instructionInfo(instruction()).ret;
|
return static_cast<size_t>(instructionInfo(instruction()).ret);
|
||||||
case Push:
|
case Push:
|
||||||
case PushString:
|
case PushString:
|
||||||
case PushTag:
|
case PushTag:
|
||||||
@ -193,7 +193,7 @@ string AssemblyItem::toAssemblyText() const
|
|||||||
size_t sub{0};
|
size_t sub{0};
|
||||||
size_t tag{0};
|
size_t tag{0};
|
||||||
tie(sub, tag) = splitForeignPushTag();
|
tie(sub, tag) = splitForeignPushTag();
|
||||||
if (sub == size_t(-1))
|
if (sub == numeric_limits<size_t>::max())
|
||||||
text = string("tag_") + to_string(tag);
|
text = string("tag_") + to_string(tag);
|
||||||
else
|
else
|
||||||
text = string("tag_") + to_string(sub) + "_" + to_string(tag);
|
text = string("tag_") + to_string(sub) + "_" + to_string(tag);
|
||||||
@ -201,16 +201,16 @@ string AssemblyItem::toAssemblyText() const
|
|||||||
}
|
}
|
||||||
case Tag:
|
case Tag:
|
||||||
assertThrow(data() < 0x10000, AssemblyException, "Declaration of sub-assembly tag.");
|
assertThrow(data() < 0x10000, AssemblyException, "Declaration of sub-assembly tag.");
|
||||||
text = string("tag_") + to_string(size_t(data())) + ":";
|
text = string("tag_") + to_string(static_cast<size_t>(data())) + ":";
|
||||||
break;
|
break;
|
||||||
case PushData:
|
case PushData:
|
||||||
text = string("data_") + util::toHex(data());
|
text = string("data_") + util::toHex(data());
|
||||||
break;
|
break;
|
||||||
case PushSub:
|
case PushSub:
|
||||||
text = string("dataOffset(sub_") + to_string(size_t(data())) + ")";
|
text = string("dataOffset(sub_") + to_string(static_cast<size_t>(data())) + ")";
|
||||||
break;
|
break;
|
||||||
case PushSubSize:
|
case PushSubSize:
|
||||||
text = string("dataSize(sub_") + to_string(size_t(data())) + ")";
|
text = string("dataSize(sub_") + to_string(static_cast<size_t>(data())) + ")";
|
||||||
break;
|
break;
|
||||||
case PushProgramSize:
|
case PushProgramSize:
|
||||||
text = string("bytecodeSize");
|
text = string("bytecodeSize");
|
||||||
@ -262,7 +262,7 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item)
|
|||||||
case PushTag:
|
case PushTag:
|
||||||
{
|
{
|
||||||
size_t subId = _item.splitForeignPushTag().first;
|
size_t subId = _item.splitForeignPushTag().first;
|
||||||
if (subId == size_t(-1))
|
if (subId == numeric_limits<size_t>::max())
|
||||||
_out << " PushTag " << _item.splitForeignPushTag().second;
|
_out << " PushTag " << _item.splitForeignPushTag().second;
|
||||||
else
|
else
|
||||||
_out << " PushTag " << subId << ":" << _item.splitForeignPushTag().second;
|
_out << " PushTag " << subId << ":" << _item.splitForeignPushTag().second;
|
||||||
@ -272,13 +272,13 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item)
|
|||||||
_out << " Tag " << _item.data();
|
_out << " Tag " << _item.data();
|
||||||
break;
|
break;
|
||||||
case PushData:
|
case PushData:
|
||||||
_out << " PushData " << hex << (unsigned)_item.data() << dec;
|
_out << " PushData " << hex << static_cast<unsigned>(_item.data()) << dec;
|
||||||
break;
|
break;
|
||||||
case PushSub:
|
case PushSub:
|
||||||
_out << " PushSub " << hex << size_t(_item.data()) << dec;
|
_out << " PushSub " << hex << static_cast<size_t>(_item.data()) << dec;
|
||||||
break;
|
break;
|
||||||
case PushSubSize:
|
case PushSubSize:
|
||||||
_out << " PushSubSize " << hex << size_t(_item.data()) << dec;
|
_out << " PushSubSize " << hex << static_cast<size_t>(_item.data()) << dec;
|
||||||
break;
|
break;
|
||||||
case PushProgramSize:
|
case PushProgramSize:
|
||||||
_out << " PushProgramSize";
|
_out << " PushProgramSize";
|
||||||
@ -317,7 +317,7 @@ std::string AssemblyItem::computeSourceMapping(
|
|||||||
int prevStart = -1;
|
int prevStart = -1;
|
||||||
int prevLength = -1;
|
int prevLength = -1;
|
||||||
int prevSourceIndex = -1;
|
int prevSourceIndex = -1;
|
||||||
size_t prevModifierDepth = -1;
|
int prevModifierDepth = -1;
|
||||||
char prevJump = 0;
|
char prevJump = 0;
|
||||||
for (auto const& item: _items)
|
for (auto const& item: _items)
|
||||||
{
|
{
|
||||||
@ -328,14 +328,14 @@ std::string AssemblyItem::computeSourceMapping(
|
|||||||
int length = location.start != -1 && location.end != -1 ? location.end - location.start : -1;
|
int length = location.start != -1 && location.end != -1 ? location.end - location.start : -1;
|
||||||
int sourceIndex =
|
int sourceIndex =
|
||||||
location.source && _sourceIndicesMap.count(location.source->name()) ?
|
location.source && _sourceIndicesMap.count(location.source->name()) ?
|
||||||
_sourceIndicesMap.at(location.source->name()) :
|
static_cast<int>(_sourceIndicesMap.at(location.source->name())) :
|
||||||
-1;
|
-1;
|
||||||
char jump = '-';
|
char jump = '-';
|
||||||
if (item.getJumpType() == evmasm::AssemblyItem::JumpType::IntoFunction)
|
if (item.getJumpType() == evmasm::AssemblyItem::JumpType::IntoFunction)
|
||||||
jump = 'i';
|
jump = 'i';
|
||||||
else if (item.getJumpType() == evmasm::AssemblyItem::JumpType::OutOfFunction)
|
else if (item.getJumpType() == evmasm::AssemblyItem::JumpType::OutOfFunction)
|
||||||
jump = 'o';
|
jump = 'o';
|
||||||
size_t modifierDepth = item.m_modifierDepth;
|
int modifierDepth = static_cast<int>(item.m_modifierDepth);
|
||||||
|
|
||||||
unsigned components = 5;
|
unsigned components = 5;
|
||||||
if (modifierDepth == prevModifierDepth)
|
if (modifierDepth == prevModifierDepth)
|
||||||
|
@ -134,9 +134,9 @@ public:
|
|||||||
/// @returns an upper bound for the number of bytes required by this item, assuming that
|
/// @returns an upper bound for the number of bytes required by this item, assuming that
|
||||||
/// the value of a jump tag takes @a _addressLength bytes.
|
/// the value of a jump tag takes @a _addressLength bytes.
|
||||||
unsigned bytesRequired(unsigned _addressLength) const;
|
unsigned bytesRequired(unsigned _addressLength) const;
|
||||||
int arguments() const;
|
size_t arguments() const;
|
||||||
int returnValues() const;
|
size_t returnValues() const;
|
||||||
int deposit() const { return returnValues() - arguments(); }
|
size_t deposit() const { return returnValues() - arguments(); }
|
||||||
|
|
||||||
/// @returns true if the assembly item can be used in a functional context.
|
/// @returns true if the assembly item can be used in a functional context.
|
||||||
bool canBeFunctional() const;
|
bool canBeFunctional() const;
|
||||||
|
@ -63,8 +63,9 @@ bool BlockDeduplicator::deduplicate()
|
|||||||
if (_j < m_items.size() && m_items.at(_j).type() == Tag)
|
if (_j < m_items.size() && m_items.at(_j).type() == Tag)
|
||||||
pushSecondTag = m_items.at(_j).pushTag();
|
pushSecondTag = m_items.at(_j).pushTag();
|
||||||
|
|
||||||
BlockIterator first{m_items.begin() + _i, m_items.end(), &pushFirstTag, &pushSelf};
|
using diff_type = BlockIterator::difference_type;
|
||||||
BlockIterator second{m_items.begin() + _j, m_items.end(), &pushSecondTag, &pushSelf};
|
BlockIterator first{m_items.begin() + diff_type(_i), m_items.end(), &pushFirstTag, &pushSelf};
|
||||||
|
BlockIterator second{m_items.begin() + diff_type(_j), m_items.end(), &pushSecondTag, &pushSelf};
|
||||||
BlockIterator end{m_items.end(), m_items.end()};
|
BlockIterator end{m_items.end(), m_items.end()};
|
||||||
|
|
||||||
if (first != end && (*first).type() == Tag)
|
if (first != end && (*first).type() == Tag)
|
||||||
@ -120,7 +121,7 @@ bool BlockDeduplicator::applyTagReplacement(
|
|||||||
if (it != _replacements.end())
|
if (it != _replacements.end())
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
item.setPushTagSubIdAndTag(subId, size_t(it->second));
|
item.setPushTagSubIdAndTag(subId, static_cast<size_t>(it->second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -386,7 +386,11 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
|
|||||||
"Opcodes with more than two arguments not implemented yet."
|
"Opcodes with more than two arguments not implemented yet."
|
||||||
);
|
);
|
||||||
for (size_t i = 0; i < arguments.size(); ++i)
|
for (size_t i = 0; i < arguments.size(); ++i)
|
||||||
assertThrow(m_stack[m_stackHeight - i] == arguments[i], OptimizerException, "Expected arguments not present." );
|
assertThrow(
|
||||||
|
m_stack[m_stackHeight - static_cast<int>(i)] == arguments[i],
|
||||||
|
OptimizerException,
|
||||||
|
"Expected arguments not present."
|
||||||
|
);
|
||||||
|
|
||||||
while (SemanticInformation::isCommutativeOperation(*expr.item) &&
|
while (SemanticInformation::isCommutativeOperation(*expr.item) &&
|
||||||
!m_generatedItems.empty() &&
|
!m_generatedItems.empty() &&
|
||||||
@ -395,8 +399,8 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
|
|||||||
appendOrRemoveSwap(m_stackHeight - 1, itemLocation);
|
appendOrRemoveSwap(m_stackHeight - 1, itemLocation);
|
||||||
for (size_t i = 0; i < arguments.size(); ++i)
|
for (size_t i = 0; i < arguments.size(); ++i)
|
||||||
{
|
{
|
||||||
m_classPositions[m_stack[m_stackHeight - i]].erase(m_stackHeight - i);
|
m_classPositions[m_stack[m_stackHeight - static_cast<int>(i)]].erase(m_stackHeight - static_cast<int>(i));
|
||||||
m_stack.erase(m_stackHeight - i);
|
m_stack.erase(m_stackHeight - static_cast<int>(i));
|
||||||
}
|
}
|
||||||
appendItem(*expr.item);
|
appendItem(*expr.item);
|
||||||
if (expr.item->type() != Operation || instructionInfo(expr.item->instruction()).ret == 1)
|
if (expr.item->type() != Operation || instructionInfo(expr.item->instruction()).ret == 1)
|
||||||
@ -467,7 +471,7 @@ void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _locat
|
|||||||
int instructionNum = 1 + m_stackHeight - _fromPosition;
|
int instructionNum = 1 + m_stackHeight - _fromPosition;
|
||||||
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables.");
|
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables.");
|
||||||
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
||||||
appendItem(AssemblyItem(dupInstruction(instructionNum), _location));
|
appendItem(AssemblyItem(dupInstruction(static_cast<unsigned>(instructionNum)), _location));
|
||||||
m_stack[m_stackHeight] = m_stack[_fromPosition];
|
m_stack[m_stackHeight] = m_stack[_fromPosition];
|
||||||
m_classPositions[m_stack[m_stackHeight]].insert(m_stackHeight);
|
m_classPositions[m_stack[m_stackHeight]].insert(m_stackHeight);
|
||||||
}
|
}
|
||||||
@ -480,7 +484,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons
|
|||||||
int instructionNum = m_stackHeight - _fromPosition;
|
int instructionNum = m_stackHeight - _fromPosition;
|
||||||
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables.");
|
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables.");
|
||||||
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
||||||
appendItem(AssemblyItem(swapInstruction(instructionNum), _location));
|
appendItem(AssemblyItem(swapInstruction(static_cast<unsigned>(instructionNum)), _location));
|
||||||
|
|
||||||
if (m_stack[m_stackHeight] != m_stack[_fromPosition])
|
if (m_stack[m_stackHeight] != m_stack[_fromPosition])
|
||||||
{
|
{
|
||||||
@ -502,5 +506,5 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons
|
|||||||
void CSECodeGenerator::appendItem(AssemblyItem const& _item)
|
void CSECodeGenerator::appendItem(AssemblyItem const& _item)
|
||||||
{
|
{
|
||||||
m_generatedItems.push_back(_item);
|
m_generatedItems.push_back(_item);
|
||||||
m_stackHeight += _item.deposit();
|
m_stackHeight += static_cast<int>(_item.deposit());
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
|
|||||||
{
|
{
|
||||||
case Operation:
|
case Operation:
|
||||||
{
|
{
|
||||||
if (stack.size() < size_t(item.arguments()))
|
if (stack.size() < item.arguments())
|
||||||
return false;
|
return false;
|
||||||
u256* sp = &stack.back();
|
u256* sp = &stack.back();
|
||||||
switch (item.instruction())
|
switch (item.instruction())
|
||||||
@ -320,7 +320,7 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
|
|||||||
|
|
||||||
bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
|
bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
|
||||||
{
|
{
|
||||||
size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP);
|
auto numExps = static_cast<size_t>(count(_routine.begin(), _routine.end(), Instruction::EXP));
|
||||||
return combineGas(
|
return combineGas(
|
||||||
simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)),
|
simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)),
|
||||||
// Data gas for routine: Some bytes are zero, but we ignore them.
|
// Data gas for routine: Some bytes are zero, but we ignore them.
|
||||||
|
@ -45,8 +45,8 @@ public:
|
|||||||
BlockId() { *this = invalid(); }
|
BlockId() { *this = invalid(); }
|
||||||
explicit BlockId(unsigned _id): m_id(_id) {}
|
explicit BlockId(unsigned _id): m_id(_id) {}
|
||||||
explicit BlockId(u256 const& _id);
|
explicit BlockId(u256 const& _id);
|
||||||
static BlockId initial() { return BlockId(-2); }
|
static BlockId initial() { return BlockId(std::numeric_limits<unsigned>::max() - 1); }
|
||||||
static BlockId invalid() { return BlockId(-1); }
|
static BlockId invalid() { return BlockId(std::numeric_limits<unsigned>::max()); }
|
||||||
|
|
||||||
bool operator==(BlockId const& _other) const { return m_id == _other.m_id; }
|
bool operator==(BlockId const& _other) const { return m_id == _other.m_id; }
|
||||||
bool operator!=(BlockId const& _other) const { return m_id != _other.m_id; }
|
bool operator!=(BlockId const& _other) const { return m_id != _other.m_id; }
|
||||||
|
@ -190,7 +190,7 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr)
|
|||||||
_expr.item->type() != Operation ||
|
_expr.item->type() != Operation ||
|
||||||
!SemanticInformation::isDeterministic(*_expr.item)
|
!SemanticInformation::isDeterministic(*_expr.item)
|
||||||
)
|
)
|
||||||
return -1;
|
return numeric_limits<unsigned>::max();
|
||||||
|
|
||||||
if (auto match = rules.findFirstMatch(_expr, *this))
|
if (auto match = rules.findFirstMatch(_expr, *this))
|
||||||
{
|
{
|
||||||
@ -208,7 +208,7 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr)
|
|||||||
return rebuildExpression(ExpressionTemplate(match->action(), _expr.item->location()));
|
return rebuildExpression(ExpressionTemplate(match->action(), _expr.item->location()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return numeric_limits<unsigned>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionClasses::Id ExpressionClasses::rebuildExpression(ExpressionTemplate const& _template)
|
ExpressionClasses::Id ExpressionClasses::rebuildExpression(ExpressionTemplate const& _template)
|
||||||
|
@ -330,8 +330,8 @@ void solidity::evmasm::eachInstruction(
|
|||||||
{
|
{
|
||||||
for (auto it = _mem.begin(); it < _mem.end(); ++it)
|
for (auto it = _mem.begin(); it < _mem.end(); ++it)
|
||||||
{
|
{
|
||||||
Instruction instr = Instruction(*it);
|
auto instr = Instruction(*it);
|
||||||
size_t additional = 0;
|
int additional = 0;
|
||||||
if (isValidInstruction(instr))
|
if (isValidInstruction(instr))
|
||||||
additional = instructionInfo(instr).additional;
|
additional = instructionInfo(instr).additional;
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ string solidity::evmasm::disassemble(bytes const& _mem)
|
|||||||
stringstream ret;
|
stringstream ret;
|
||||||
eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) {
|
eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) {
|
||||||
if (!isValidInstruction(_instr))
|
if (!isValidInstruction(_instr))
|
||||||
ret << "0x" << std::uppercase << std::hex << int(_instr) << " ";
|
ret << "0x" << std::uppercase << std::hex << static_cast<int>(_instr) << " ";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InstructionInfo info = instructionInfo(_instr);
|
InstructionInfo info = instructionInfo(_instr);
|
||||||
|
@ -30,7 +30,7 @@ using namespace solidity::evmasm;
|
|||||||
|
|
||||||
bool JumpdestRemover::optimise(set<size_t> const& _tagsReferencedFromOutside)
|
bool JumpdestRemover::optimise(set<size_t> const& _tagsReferencedFromOutside)
|
||||||
{
|
{
|
||||||
set<size_t> references{referencedTags(m_items, -1)};
|
set<size_t> references{referencedTags(m_items, numeric_limits<size_t>::max())};
|
||||||
references.insert(_tagsReferencedFromOutside.begin(), _tagsReferencedFromOutside.end());
|
references.insert(_tagsReferencedFromOutside.begin(), _tagsReferencedFromOutside.end());
|
||||||
|
|
||||||
size_t initialSize = m_items.size();
|
size_t initialSize = m_items.size();
|
||||||
@ -43,7 +43,7 @@ bool JumpdestRemover::optimise(set<size_t> const& _tagsReferencedFromOutside)
|
|||||||
if (_item.type() != Tag)
|
if (_item.type() != Tag)
|
||||||
return false;
|
return false;
|
||||||
auto asmIdAndTag = _item.splitForeignPushTag();
|
auto asmIdAndTag = _item.splitForeignPushTag();
|
||||||
assertThrow(asmIdAndTag.first == size_t(-1), OptimizerException, "Sub-assembly tag used as label.");
|
assertThrow(asmIdAndTag.first == numeric_limits<size_t>::max(), OptimizerException, "Sub-assembly tag used as label.");
|
||||||
size_t tag = asmIdAndTag.second;
|
size_t tag = asmIdAndTag.second;
|
||||||
return !references.count(tag);
|
return !references.count(tag);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ ostream& KnownState::stream(ostream& _out) const
|
|||||||
if (!expr.item)
|
if (!expr.item)
|
||||||
_out << " no item";
|
_out << " no item";
|
||||||
else if (expr.item->type() == UndefinedItem)
|
else if (expr.item->type() == UndefinedItem)
|
||||||
_out << " unknown " << int(expr.item->data());
|
_out << " unknown " << static_cast<int>(expr.item->data());
|
||||||
else
|
else
|
||||||
_out << *expr.item;
|
_out << *expr.item;
|
||||||
if (expr.sequenceNumber)
|
if (expr.sequenceNumber)
|
||||||
@ -112,21 +112,21 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
|
|||||||
setStackElement(
|
setStackElement(
|
||||||
m_stackHeight + 1,
|
m_stackHeight + 1,
|
||||||
stackElement(
|
stackElement(
|
||||||
m_stackHeight - int(instruction) + int(Instruction::DUP1),
|
m_stackHeight - static_cast<int>(instruction) + static_cast<int>(Instruction::DUP1),
|
||||||
_item.location()
|
_item.location()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
else if (SemanticInformation::isSwapInstruction(_item))
|
else if (SemanticInformation::isSwapInstruction(_item))
|
||||||
swapStackElements(
|
swapStackElements(
|
||||||
m_stackHeight,
|
m_stackHeight,
|
||||||
m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1),
|
m_stackHeight - 1 - static_cast<int>(instruction) + static_cast<int>(Instruction::SWAP1),
|
||||||
_item.location()
|
_item.location()
|
||||||
);
|
);
|
||||||
else if (instruction != Instruction::POP)
|
else if (instruction != Instruction::POP)
|
||||||
{
|
{
|
||||||
vector<Id> arguments(info.args);
|
vector<Id> arguments(static_cast<size_t>(info.args));
|
||||||
for (int i = 0; i < info.args; ++i)
|
for (size_t i = 0; i < static_cast<size_t>(info.args); ++i)
|
||||||
arguments[i] = stackElement(m_stackHeight - i, _item.location());
|
arguments[i] = stackElement(m_stackHeight - static_cast<int>(i), _item.location());
|
||||||
switch (_item.instruction())
|
switch (_item.instruction())
|
||||||
{
|
{
|
||||||
case Instruction::SSTORE:
|
case Instruction::SSTORE:
|
||||||
@ -134,7 +134,7 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
|
|||||||
break;
|
break;
|
||||||
case Instruction::SLOAD:
|
case Instruction::SLOAD:
|
||||||
setStackElement(
|
setStackElement(
|
||||||
m_stackHeight + _item.deposit(),
|
m_stackHeight + static_cast<int>(_item.deposit()),
|
||||||
loadFromStorage(arguments[0], _item.location())
|
loadFromStorage(arguments[0], _item.location())
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -143,13 +143,13 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
|
|||||||
break;
|
break;
|
||||||
case Instruction::MLOAD:
|
case Instruction::MLOAD:
|
||||||
setStackElement(
|
setStackElement(
|
||||||
m_stackHeight + _item.deposit(),
|
m_stackHeight + static_cast<int>(_item.deposit()),
|
||||||
loadFromMemory(arguments[0], _item.location())
|
loadFromMemory(arguments[0], _item.location())
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case Instruction::KECCAK256:
|
case Instruction::KECCAK256:
|
||||||
setStackElement(
|
setStackElement(
|
||||||
m_stackHeight + _item.deposit(),
|
m_stackHeight + static_cast<int>(_item.deposit()),
|
||||||
applyKeccak256(arguments.at(0), arguments.at(1), _item.location())
|
applyKeccak256(arguments.at(0), arguments.at(1), _item.location())
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -167,16 +167,16 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
|
|||||||
assertThrow(info.ret <= 1, InvalidDeposit, "");
|
assertThrow(info.ret <= 1, InvalidDeposit, "");
|
||||||
if (info.ret == 1)
|
if (info.ret == 1)
|
||||||
setStackElement(
|
setStackElement(
|
||||||
m_stackHeight + _item.deposit(),
|
m_stackHeight + static_cast<int>(_item.deposit()),
|
||||||
m_expressionClasses->find(_item, arguments, _copyItem)
|
m_expressionClasses->find(_item, arguments, _copyItem)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_stackElements.erase(
|
m_stackElements.erase(
|
||||||
m_stackElements.upper_bound(m_stackHeight + _item.deposit()),
|
m_stackElements.upper_bound(m_stackHeight + static_cast<int>(_item.deposit())),
|
||||||
m_stackElements.end()
|
m_stackElements.end()
|
||||||
);
|
);
|
||||||
m_stackHeight += _item.deposit();
|
m_stackHeight += static_cast<int>(_item.deposit());
|
||||||
}
|
}
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
@ -388,7 +388,7 @@ KnownState::Id KnownState::applyKeccak256(
|
|||||||
bytes data;
|
bytes data;
|
||||||
for (Id a: arguments)
|
for (Id a: arguments)
|
||||||
data += util::toBigEndian(*m_expressionClasses->knownConstant(a));
|
data += util::toBigEndian(*m_expressionClasses->knownConstant(a));
|
||||||
data.resize(size_t(*l));
|
data.resize(static_cast<size_t>(*l));
|
||||||
v = m_expressionClasses->find(AssemblyItem(u256(util::keccak256(data)), _location));
|
v = m_expressionClasses->find(AssemblyItem(u256(util::keccak256(data)), _location));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -40,7 +40,7 @@ void LinkerObject::link(map<string, h160> const& _libraryAddresses)
|
|||||||
std::map<size_t, std::string> remainingRefs;
|
std::map<size_t, std::string> remainingRefs;
|
||||||
for (auto const& linkRef: linkReferences)
|
for (auto const& linkRef: linkReferences)
|
||||||
if (h160 const* address = matchLibrary(linkRef.second, _libraryAddresses))
|
if (h160 const* address = matchLibrary(linkRef.second, _libraryAddresses))
|
||||||
copy(address->data(), address->data() + 20, bytecode.begin() + linkRef.first);
|
copy(address->data(), address->data() + 20, bytecode.begin() + vector<uint8_t>::difference_type(linkRef.first));
|
||||||
else
|
else
|
||||||
remainingRefs.insert(linkRef);
|
remainingRefs.insert(linkRef);
|
||||||
linkReferences.swap(remainingRefs);
|
linkReferences.swap(remainingRefs);
|
||||||
|
@ -84,7 +84,7 @@ struct SimplePeepholeOptimizerMethod
|
|||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
_state.i + WindowSize <= _state.items.size() &&
|
_state.i + WindowSize <= _state.items.size() &&
|
||||||
ApplyRule<Method, WindowSize>::applyRule(_state.items.begin() + _state.i, _state.out)
|
ApplyRule<Method, WindowSize>::applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_state.i += WindowSize;
|
_state.i += WindowSize;
|
||||||
@ -303,7 +303,7 @@ struct UnreachableCode
|
|||||||
{
|
{
|
||||||
static bool apply(OptimiserState& _state)
|
static bool apply(OptimiserState& _state)
|
||||||
{
|
{
|
||||||
auto it = _state.items.begin() + _state.i;
|
auto it = _state.items.begin() + static_cast<ptrdiff_t>(_state.i);
|
||||||
auto end = _state.items.end();
|
auto end = _state.items.end();
|
||||||
if (it == end)
|
if (it == end)
|
||||||
return false;
|
return false;
|
||||||
@ -317,13 +317,13 @@ struct UnreachableCode
|
|||||||
)
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
size_t i = 1;
|
ptrdiff_t i = 1;
|
||||||
while (it + i != end && it[i].type() != Tag)
|
while (it + i != end && it[i].type() != Tag)
|
||||||
i++;
|
i++;
|
||||||
if (i > 1)
|
if (i > 1)
|
||||||
{
|
{
|
||||||
*_state.out = it[0];
|
*_state.out = it[0];
|
||||||
_state.i += i;
|
_state.i += static_cast<size_t>(i);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -345,7 +345,7 @@ void applyMethods(OptimiserState& _state, Method, OtherMethods... _other)
|
|||||||
|
|
||||||
size_t numberOfPops(AssemblyItems const& _items)
|
size_t numberOfPops(AssemblyItems const& _items)
|
||||||
{
|
{
|
||||||
return std::count(_items.begin(), _items.end(), Instruction::POP);
|
return static_cast<size_t>(std::count(_items.begin(), _items.end(), Instruction::POP));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ string CharStream::lineAtPosition(int _position) const
|
|||||||
{
|
{
|
||||||
// if _position points to \n, it returns the line before the \n
|
// if _position points to \n, it returns the line before the \n
|
||||||
using size_type = string::size_type;
|
using size_type = string::size_type;
|
||||||
size_type searchStart = min<size_type>(m_source.size(), _position);
|
size_type searchStart = min<size_type>(m_source.size(), size_type(_position));
|
||||||
if (searchStart > 0)
|
if (searchStart > 0)
|
||||||
searchStart--;
|
searchStart--;
|
||||||
size_type lineStart = m_source.rfind('\n', searchStart);
|
size_type lineStart = m_source.rfind('\n', searchStart);
|
||||||
@ -105,8 +105,9 @@ string CharStream::lineAtPosition(int _position) const
|
|||||||
tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
|
tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
|
||||||
{
|
{
|
||||||
using size_type = string::size_type;
|
using size_type = string::size_type;
|
||||||
size_type searchPosition = min<size_type>(m_source.size(), _position);
|
using diff_type = string::difference_type;
|
||||||
int lineNumber = count(m_source.begin(), m_source.begin() + searchPosition, '\n');
|
size_type searchPosition = min<size_type>(m_source.size(), size_type(_position));
|
||||||
|
int lineNumber = count(m_source.begin(), m_source.begin() + diff_type(searchPosition), '\n');
|
||||||
size_type lineStart;
|
size_type lineStart;
|
||||||
if (searchPosition == 0)
|
if (searchPosition == 0)
|
||||||
lineStart = 0;
|
lineStart = 0;
|
||||||
|
@ -72,7 +72,7 @@ public:
|
|||||||
explicit CharStream(std::string _source, std::string name):
|
explicit CharStream(std::string _source, std::string name):
|
||||||
m_source(std::move(_source)), m_name(std::move(name)) {}
|
m_source(std::move(_source)), m_name(std::move(name)) {}
|
||||||
|
|
||||||
int position() const { return m_position; }
|
size_t position() const { return m_position; }
|
||||||
bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_position + _charsForward) >= m_source.size(); }
|
bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_position + _charsForward) >= m_source.size(); }
|
||||||
|
|
||||||
char get(size_t _charsForward = 0) const { return m_source[m_position + _charsForward]; }
|
char get(size_t _charsForward = 0) const { return m_source[m_position + _charsForward]; }
|
||||||
|
@ -106,7 +106,7 @@ void ParserBase::expectTokenOrConsumeUntil(Token _value, string const& _currentN
|
|||||||
if (m_scanner->currentToken() == Token::EOS)
|
if (m_scanner->currentToken() == Token::EOS)
|
||||||
{
|
{
|
||||||
// rollback to where the token started, and raise exception to be caught at a higher level.
|
// rollback to where the token started, and raise exception to be caught at a higher level.
|
||||||
m_scanner->setPosition(startPosition);
|
m_scanner->setPosition(static_cast<size_t>(startPosition));
|
||||||
m_inParserRecovery = true;
|
m_inParserRecovery = true;
|
||||||
fatalParserError(1957_error, errorLoc, msg);
|
fatalParserError(1957_error, errorLoc, msg);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ void Scanner::supportPeriodInIdentifier(bool _value)
|
|||||||
bool Scanner::scanHexByte(char& o_scannedByte)
|
bool Scanner::scanHexByte(char& o_scannedByte)
|
||||||
{
|
{
|
||||||
char x = 0;
|
char x = 0;
|
||||||
for (int i = 0; i < 2; i++)
|
for (size_t i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
int d = hexValue(m_char);
|
int d = hexValue(m_char);
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
@ -189,7 +189,7 @@ bool Scanner::scanHexByte(char& o_scannedByte)
|
|||||||
std::optional<unsigned> Scanner::scanUnicode()
|
std::optional<unsigned> Scanner::scanUnicode()
|
||||||
{
|
{
|
||||||
unsigned x = 0;
|
unsigned x = 0;
|
||||||
for (int i = 0; i < 4; i++)
|
for (size_t i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
int d = hexValue(m_char);
|
int d = hexValue(m_char);
|
||||||
if (d < 0)
|
if (d < 0)
|
||||||
@ -197,7 +197,7 @@ std::optional<unsigned> Scanner::scanUnicode()
|
|||||||
rollback(i);
|
rollback(i);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
x = x * 16 + d;
|
x = x * 16 + static_cast<size_t>(d);
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
@ -207,17 +207,17 @@ std::optional<unsigned> Scanner::scanUnicode()
|
|||||||
void Scanner::addUnicodeAsUTF8(unsigned codepoint)
|
void Scanner::addUnicodeAsUTF8(unsigned codepoint)
|
||||||
{
|
{
|
||||||
if (codepoint <= 0x7f)
|
if (codepoint <= 0x7f)
|
||||||
addLiteralChar(codepoint);
|
addLiteralChar(char(codepoint));
|
||||||
else if (codepoint <= 0x7ff)
|
else if (codepoint <= 0x7ff)
|
||||||
{
|
{
|
||||||
addLiteralChar(0xc0 | (codepoint >> 6));
|
addLiteralChar(char(0xc0u | (codepoint >> 6u)));
|
||||||
addLiteralChar(0x80 | (codepoint & 0x3f));
|
addLiteralChar(char(0x80u | (codepoint & 0x3fu)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addLiteralChar(0xe0 | (codepoint >> 12));
|
addLiteralChar(char(0xe0u | (codepoint >> 12u)));
|
||||||
addLiteralChar(0x80 | ((codepoint >> 6) & 0x3f));
|
addLiteralChar(char(0x80u | ((codepoint >> 6u) & 0x3fu)));
|
||||||
addLiteralChar(0x80 | (codepoint & 0x3f));
|
addLiteralChar(char(0x80u | (codepoint & 0x3fu)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,10 +225,10 @@ void Scanner::rescan()
|
|||||||
{
|
{
|
||||||
size_t rollbackTo = 0;
|
size_t rollbackTo = 0;
|
||||||
if (m_skippedComments[Current].literal.empty())
|
if (m_skippedComments[Current].literal.empty())
|
||||||
rollbackTo = m_tokens[Current].location.start;
|
rollbackTo = static_cast<size_t>(m_tokens[Current].location.start);
|
||||||
else
|
else
|
||||||
rollbackTo = m_skippedComments[Current].location.start;
|
rollbackTo = static_cast<size_t>(m_skippedComments[Current].location.start);
|
||||||
m_char = m_source->rollback(size_t(m_source->position()) - rollbackTo);
|
m_char = m_source->rollback(m_source->position() - rollbackTo);
|
||||||
next();
|
next();
|
||||||
next();
|
next();
|
||||||
next();
|
next();
|
||||||
@ -260,7 +260,7 @@ Token Scanner::selectToken(char _next, Token _then, Token _else)
|
|||||||
|
|
||||||
bool Scanner::skipWhitespace()
|
bool Scanner::skipWhitespace()
|
||||||
{
|
{
|
||||||
int const startPosition = sourcePos();
|
size_t const startPosition = sourcePos();
|
||||||
while (isWhiteSpace(m_char))
|
while (isWhiteSpace(m_char))
|
||||||
advance();
|
advance();
|
||||||
// Return whether or not we skipped any characters.
|
// Return whether or not we skipped any characters.
|
||||||
@ -269,7 +269,7 @@ bool Scanner::skipWhitespace()
|
|||||||
|
|
||||||
bool Scanner::skipWhitespaceExceptUnicodeLinebreak()
|
bool Scanner::skipWhitespaceExceptUnicodeLinebreak()
|
||||||
{
|
{
|
||||||
int const startPosition = sourcePos();
|
size_t const startPosition = sourcePos();
|
||||||
while (isWhiteSpace(m_char) && !isUnicodeLinebreak())
|
while (isWhiteSpace(m_char) && !isUnicodeLinebreak())
|
||||||
advance();
|
advance();
|
||||||
// Return whether or not we skipped any characters.
|
// Return whether or not we skipped any characters.
|
||||||
@ -309,10 +309,10 @@ bool Scanner::tryScanEndOfLine()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Scanner::scanSingleLineDocComment()
|
size_t Scanner::scanSingleLineDocComment()
|
||||||
{
|
{
|
||||||
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
|
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
|
||||||
int endPosition = m_source->position();
|
size_t endPosition = m_source->position();
|
||||||
advance(); //consume the last '/' at ///
|
advance(); //consume the last '/' at ///
|
||||||
|
|
||||||
skipWhitespaceExceptUnicodeLinebreak();
|
skipWhitespaceExceptUnicodeLinebreak();
|
||||||
@ -429,7 +429,7 @@ Token Scanner::scanMultiLineDocComment()
|
|||||||
|
|
||||||
Token Scanner::scanSlash()
|
Token Scanner::scanSlash()
|
||||||
{
|
{
|
||||||
int firstSlashPosition = sourcePos();
|
int firstSlashPosition = static_cast<int>(sourcePos());
|
||||||
advance();
|
advance();
|
||||||
if (m_char == '/')
|
if (m_char == '/')
|
||||||
{
|
{
|
||||||
@ -441,7 +441,7 @@ Token Scanner::scanSlash()
|
|||||||
m_skippedComments[NextNext].location.start = firstSlashPosition;
|
m_skippedComments[NextNext].location.start = firstSlashPosition;
|
||||||
m_skippedComments[NextNext].location.source = m_source;
|
m_skippedComments[NextNext].location.source = m_source;
|
||||||
m_skippedComments[NextNext].token = Token::CommentLiteral;
|
m_skippedComments[NextNext].token = Token::CommentLiteral;
|
||||||
m_skippedComments[NextNext].location.end = scanSingleLineDocComment();
|
m_skippedComments[NextNext].location.end = static_cast<int>(scanSingleLineDocComment());
|
||||||
return Token::Whitespace;
|
return Token::Whitespace;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -467,7 +467,7 @@ Token Scanner::scanSlash()
|
|||||||
m_skippedComments[NextNext].location.start = firstSlashPosition;
|
m_skippedComments[NextNext].location.start = firstSlashPosition;
|
||||||
m_skippedComments[NextNext].location.source = m_source;
|
m_skippedComments[NextNext].location.source = m_source;
|
||||||
comment = scanMultiLineDocComment();
|
comment = scanMultiLineDocComment();
|
||||||
m_skippedComments[NextNext].location.end = sourcePos();
|
m_skippedComments[NextNext].location.end = static_cast<int>(sourcePos());
|
||||||
m_skippedComments[NextNext].token = comment;
|
m_skippedComments[NextNext].token = comment;
|
||||||
if (comment == Token::Illegal)
|
if (comment == Token::Illegal)
|
||||||
return Token::Illegal; // error already set
|
return Token::Illegal; // error already set
|
||||||
@ -495,7 +495,7 @@ void Scanner::scanToken()
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Remember the position of the next token
|
// Remember the position of the next token
|
||||||
m_tokens[NextNext].location.start = sourcePos();
|
m_tokens[NextNext].location.start = static_cast<int>(sourcePos());
|
||||||
switch (m_char)
|
switch (m_char)
|
||||||
{
|
{
|
||||||
case '"':
|
case '"':
|
||||||
@ -690,7 +690,7 @@ void Scanner::scanToken()
|
|||||||
// whitespace.
|
// whitespace.
|
||||||
}
|
}
|
||||||
while (token == Token::Whitespace);
|
while (token == Token::Whitespace);
|
||||||
m_tokens[NextNext].location.end = sourcePos();
|
m_tokens[NextNext].location.end = static_cast<int>(sourcePos());
|
||||||
m_tokens[NextNext].location.source = m_source;
|
m_tokens[NextNext].location.source = m_source;
|
||||||
m_tokens[NextNext].token = token;
|
m_tokens[NextNext].token = token;
|
||||||
m_tokens[NextNext].extendedTokenInfo = make_tuple(m, n);
|
m_tokens[NextNext].extendedTokenInfo = make_tuple(m, n);
|
||||||
|
@ -196,7 +196,7 @@ private:
|
|||||||
///@}
|
///@}
|
||||||
|
|
||||||
bool advance() { m_char = m_source->advanceAndGet(); return !m_source->isPastEndOfInput(); }
|
bool advance() { m_char = m_source->advanceAndGet(); return !m_source->isPastEndOfInput(); }
|
||||||
void rollback(int _amount) { m_char = m_source->rollback(_amount); }
|
void rollback(size_t _amount) { m_char = m_source->rollback(_amount); }
|
||||||
/// Rolls back to the start of the current token and re-runs the scanner.
|
/// Rolls back to the start of the current token and re-runs the scanner.
|
||||||
void rescan();
|
void rescan();
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ private:
|
|||||||
Token scanString();
|
Token scanString();
|
||||||
Token scanHexString();
|
Token scanHexString();
|
||||||
/// Scans a single line comment and returns its corrected end position.
|
/// Scans a single line comment and returns its corrected end position.
|
||||||
int scanSingleLineDocComment();
|
size_t scanSingleLineDocComment();
|
||||||
Token scanMultiLineDocComment();
|
Token scanMultiLineDocComment();
|
||||||
/// Scans a slash '/' and depending on the characters returns the appropriate token
|
/// Scans a slash '/' and depending on the characters returns the appropriate token
|
||||||
Token scanSlash();
|
Token scanSlash();
|
||||||
@ -245,7 +245,7 @@ private:
|
|||||||
bool isUnicodeLinebreak();
|
bool isUnicodeLinebreak();
|
||||||
|
|
||||||
/// Return the current source position.
|
/// Return the current source position.
|
||||||
int sourcePos() const { return m_source->position(); }
|
size_t sourcePos() const { return m_source->position(); }
|
||||||
bool isSourcePastEndOfInput() const { return m_source->isPastEndOfInput(); }
|
bool isSourcePastEndOfInput() const { return m_source->isPastEndOfInput(); }
|
||||||
|
|
||||||
bool m_supportPeriodInIdentifier = false;
|
bool m_supportPeriodInIdentifier = false;
|
||||||
|
@ -37,7 +37,7 @@ SemVerVersion::SemVerVersion(string const& _versionString)
|
|||||||
{
|
{
|
||||||
unsigned v = 0;
|
unsigned v = 0;
|
||||||
for (; i != end && '0' <= *i && *i <= '9'; ++i)
|
for (; i != end && '0' <= *i && *i <= '9'; ++i)
|
||||||
v = v * 10 + (*i - '0');
|
v = v * 10 + unsigned(*i - '0');
|
||||||
numbers[level] = v;
|
numbers[level] = v;
|
||||||
if (level < 2)
|
if (level < 2)
|
||||||
{
|
{
|
||||||
@ -100,10 +100,10 @@ bool SemVerMatchExpression::MatchComponent::matches(SemVerVersion const& _versio
|
|||||||
int cmp = 0;
|
int cmp = 0;
|
||||||
bool didCompare = false;
|
bool didCompare = false;
|
||||||
for (unsigned i = 0; i < levelsPresent && cmp == 0; i++)
|
for (unsigned i = 0; i < levelsPresent && cmp == 0; i++)
|
||||||
if (version.numbers[i] != unsigned(-1))
|
if (version.numbers[i] != std::numeric_limits<unsigned>::max())
|
||||||
{
|
{
|
||||||
didCompare = true;
|
didCompare = true;
|
||||||
cmp = _version.numbers[i] - version.numbers[i];
|
cmp = static_cast<int>(_version.numbers[i] - version.numbers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmp == 0 && !_version.prerelease.empty() && didCompare)
|
if (cmp == 0 && !_version.prerelease.empty() && didCompare)
|
||||||
@ -245,14 +245,14 @@ unsigned SemVerMatchExpressionParser::parseVersionPart()
|
|||||||
return 0;
|
return 0;
|
||||||
else if ('1' <= c && c <= '9')
|
else if ('1' <= c && c <= '9')
|
||||||
{
|
{
|
||||||
unsigned v = c - '0';
|
unsigned v(c - '0');
|
||||||
// If we skip to the next token, the current number is terminated.
|
// If we skip to the next token, the current number is terminated.
|
||||||
while (m_pos == startPos && '0' <= currentChar() && currentChar() <= '9')
|
while (m_pos == startPos && '0' <= currentChar() && currentChar() <= '9')
|
||||||
{
|
{
|
||||||
c = currentChar();
|
c = currentChar();
|
||||||
if (v * 10 < v || v * 10 + (c - '0') < v * 10)
|
if (v * 10 < v || v * 10 + unsigned(c - '0') < v * 10)
|
||||||
throw SemVerError();
|
throw SemVerError();
|
||||||
v = v * 10 + c - '0';
|
v = v * 10 + unsigned(c - '0');
|
||||||
nextChar();
|
nextChar();
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
|
@ -85,7 +85,7 @@ struct SourceLocation
|
|||||||
assertThrow(0 <= start, SourceLocationError, "Invalid source location.");
|
assertThrow(0 <= start, SourceLocationError, "Invalid source location.");
|
||||||
assertThrow(start <= end, SourceLocationError, "Invalid source location.");
|
assertThrow(start <= end, SourceLocationError, "Invalid source location.");
|
||||||
assertThrow(end <= int(source->source().length()), SourceLocationError, "Invalid source location.");
|
assertThrow(end <= int(source->source().length()), SourceLocationError, "Invalid source location.");
|
||||||
return source->source().substr(start, end - start);
|
return source->source().substr(size_t(start), size_t(end - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the smallest SourceLocation that contains both @param _a and @param _b.
|
/// @returns the smallest SourceLocation that contains both @param _a and @param _b.
|
||||||
@ -113,7 +113,11 @@ struct SourceLocation
|
|||||||
std::shared_ptr<CharStream> source;
|
std::shared_ptr<CharStream> source;
|
||||||
};
|
};
|
||||||
|
|
||||||
SourceLocation const parseSourceLocation(std::string const& _input, std::string const& _sourceName, size_t _maxIndex = -1);
|
SourceLocation const parseSourceLocation(
|
||||||
|
std::string const& _input,
|
||||||
|
std::string const& _sourceName,
|
||||||
|
size_t _maxIndex = std::numeric_limits<size_t>::max()
|
||||||
|
);
|
||||||
|
|
||||||
/// Stream output for Location (used e.g. in boost exceptions).
|
/// Stream output for Location (used e.g. in boost exceptions).
|
||||||
inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _location)
|
inline std::ostream& operator<<(std::ostream& _out, SourceLocation const& _location)
|
||||||
|
@ -58,11 +58,15 @@ SourceReference SourceReferenceExtractor::extract(SourceLocation const* _locatio
|
|||||||
|
|
||||||
string line = source->lineAtPosition(_location->start);
|
string line = source->lineAtPosition(_location->start);
|
||||||
|
|
||||||
int locationLength = isMultiline ? line.length() - start.column : end.column - start.column;
|
int locationLength =
|
||||||
|
isMultiline ?
|
||||||
|
int(line.length()) - start.column :
|
||||||
|
end.column - start.column;
|
||||||
|
|
||||||
if (locationLength > 150)
|
if (locationLength > 150)
|
||||||
{
|
{
|
||||||
int const lhs = start.column + 35;
|
auto const lhs = static_cast<size_t>(start.column) + 35;
|
||||||
int const rhs = (isMultiline ? line.length() : end.column) - 35;
|
string::size_type const rhs = (isMultiline ? line.length() : static_cast<size_t>(end.column)) - 35;
|
||||||
line = line.substr(0, lhs) + " ... " + line.substr(rhs);
|
line = line.substr(0, lhs) + " ... " + line.substr(rhs);
|
||||||
end.column = start.column + 75;
|
end.column = start.column + 75;
|
||||||
locationLength = 75;
|
locationLength = 75;
|
||||||
@ -70,8 +74,13 @@ SourceReference SourceReferenceExtractor::extract(SourceLocation const* _locatio
|
|||||||
|
|
||||||
if (line.length() > 150)
|
if (line.length() > 150)
|
||||||
{
|
{
|
||||||
int const len = line.length();
|
int const len = static_cast<int>(line.length());
|
||||||
line = line.substr(max(0, start.column - 35), min(start.column, 35) + min(locationLength + 35, len - start.column));
|
line = line.substr(
|
||||||
|
static_cast<size_t>(max(0, start.column - 35)),
|
||||||
|
static_cast<size_t>(min(start.column, 35)) + static_cast<size_t>(
|
||||||
|
min(locationLength + 35,len - start.column)
|
||||||
|
)
|
||||||
|
);
|
||||||
if (start.column + locationLength + 35 < len)
|
if (start.column + locationLength + 35 < len)
|
||||||
line += " ...";
|
line += " ...";
|
||||||
if (start.column > 35)
|
if (start.column > 35)
|
||||||
@ -79,7 +88,7 @@ SourceReference SourceReferenceExtractor::extract(SourceLocation const* _locatio
|
|||||||
line = " ... " + line;
|
line = " ... " + line;
|
||||||
start.column = 40;
|
start.column = 40;
|
||||||
}
|
}
|
||||||
end.column = start.column + locationLength;
|
end.column = start.column + static_cast<int>(locationLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SourceReference{
|
return SourceReference{
|
||||||
|
@ -51,7 +51,7 @@ void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref)
|
|||||||
);
|
);
|
||||||
m_stream << "^";
|
m_stream << "^";
|
||||||
if (_ref.endColumn > _ref.startColumn + 2)
|
if (_ref.endColumn > _ref.startColumn + 2)
|
||||||
m_stream << string(_ref.endColumn - _ref.startColumn - 2, '-');
|
m_stream << string(static_cast<size_t>(_ref.endColumn - _ref.startColumn - 2), '-');
|
||||||
if (_ref.endColumn > _ref.startColumn + 1)
|
if (_ref.endColumn > _ref.startColumn + 1)
|
||||||
m_stream << "^";
|
m_stream << "^";
|
||||||
m_stream << endl;
|
m_stream << endl;
|
||||||
@ -60,7 +60,7 @@ void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref)
|
|||||||
m_stream <<
|
m_stream <<
|
||||||
_ref.text <<
|
_ref.text <<
|
||||||
endl <<
|
endl <<
|
||||||
string(_ref.startColumn, ' ') <<
|
string(static_cast<size_t>(_ref.startColumn), ' ') <<
|
||||||
"^ (Relevant source part starts here and spans across multiple lines)." <<
|
"^ (Relevant source part starts here and spans across multiple lines)." <<
|
||||||
endl;
|
endl;
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _
|
|||||||
|
|
||||||
if (!_ref.multiline)
|
if (!_ref.multiline)
|
||||||
{
|
{
|
||||||
int const locationLength = _ref.endColumn - _ref.startColumn;
|
auto const locationLength = static_cast<size_t>(_ref.endColumn - _ref.startColumn);
|
||||||
|
|
||||||
// line 1:
|
// line 1:
|
||||||
m_stream << leftpad << ' ';
|
m_stream << leftpad << ' ';
|
||||||
@ -113,15 +113,17 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _
|
|||||||
|
|
||||||
// line 2:
|
// line 2:
|
||||||
frameColored() << line << " |";
|
frameColored() << line << " |";
|
||||||
m_stream << ' ' << text.substr(0, _ref.startColumn);
|
|
||||||
highlightColored() << text.substr(_ref.startColumn, locationLength);
|
m_stream << ' ' << text.substr(0, static_cast<size_t>(_ref.startColumn));
|
||||||
m_stream << text.substr(_ref.endColumn) << '\n';
|
highlightColored() << text.substr(static_cast<size_t>(_ref.startColumn), locationLength);
|
||||||
|
m_stream << text.substr(static_cast<size_t>(_ref.endColumn)) << '\n';
|
||||||
|
|
||||||
// line 3:
|
// line 3:
|
||||||
m_stream << leftpad << ' ';
|
m_stream << leftpad << ' ';
|
||||||
frameColored() << '|';
|
frameColored() << '|';
|
||||||
m_stream << ' ' << replaceNonTabs(text.substr(0, _ref.startColumn), ' ');
|
|
||||||
diagColored() << replaceNonTabs(text.substr(_ref.startColumn, locationLength), '^');
|
m_stream << ' ' << replaceNonTabs(text.substr(0, static_cast<size_t>(_ref.startColumn)), ' ');
|
||||||
|
diagColored() << replaceNonTabs(text.substr(static_cast<size_t>(_ref.startColumn), locationLength), '^');
|
||||||
m_stream << '\n';
|
m_stream << '\n';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -133,13 +135,13 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _
|
|||||||
|
|
||||||
// line 2:
|
// line 2:
|
||||||
frameColored() << line << " |";
|
frameColored() << line << " |";
|
||||||
m_stream << ' ' << text.substr(0, _ref.startColumn);
|
m_stream << ' ' << text.substr(0, static_cast<size_t>(_ref.startColumn));
|
||||||
highlightColored() << text.substr(_ref.startColumn) << '\n';
|
highlightColored() << text.substr(static_cast<size_t>(_ref.startColumn)) << '\n';
|
||||||
|
|
||||||
// line 3:
|
// line 3:
|
||||||
m_stream << leftpad << ' ';
|
m_stream << leftpad << ' ';
|
||||||
frameColored() << '|';
|
frameColored() << '|';
|
||||||
m_stream << ' ' << replaceNonTabs(text.substr(0, _ref.startColumn), ' ');
|
m_stream << ' ' << replaceNonTabs(text.substr(0, static_cast<size_t>(_ref.startColumn)), ' ');
|
||||||
diagColored() << "^ (Relevant source part starts here and spans across multiple lines).";
|
diagColored() << "^ (Relevant source part starts here and spans across multiple lines).";
|
||||||
m_stream << '\n';
|
m_stream << '\n';
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ int parseSize(string::const_iterator _begin, string::const_iterator _end)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
unsigned int m = boost::lexical_cast<int>(boost::make_iterator_range(_begin, _end));
|
int m = boost::lexical_cast<int>(boost::make_iterator_range(_begin, _end));
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
catch(boost::bad_lexical_cast const&)
|
catch(boost::bad_lexical_cast const&)
|
||||||
|
@ -481,7 +481,12 @@ void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract)
|
|||||||
for (auto const* stateVar: _contract.stateVariables())
|
for (auto const* stateVar: _contract.stateVariables())
|
||||||
{
|
{
|
||||||
if (!stateVar->isPublic())
|
if (!stateVar->isPublic())
|
||||||
|
{
|
||||||
|
if (stateVar->overrides())
|
||||||
|
m_errorReporter.typeError(8022_error, stateVar->location(), "Override can only be used with public state variables.");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (contains_if(inheritedMods, MatchByName{stateVar->name()}))
|
if (contains_if(inheritedMods, MatchByName{stateVar->name()}))
|
||||||
m_errorReporter.typeError(1456_error, stateVar->location(), "Override changes modifier to public state variable.");
|
m_errorReporter.typeError(1456_error, stateVar->location(), "Override changes modifier to public state variable.");
|
||||||
|
@ -1276,6 +1276,7 @@ string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingT
|
|||||||
|
|
||||||
string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
|
if (_type.category() == Type::Category::Function)
|
||||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||||
string functionName =
|
string functionName =
|
||||||
"read_from_storage_" +
|
"read_from_storage_" +
|
||||||
@ -1299,6 +1300,7 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool
|
|||||||
|
|
||||||
string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes)
|
string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
|
if (_type.category() == Type::Category::Function)
|
||||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||||
string functionName =
|
string functionName =
|
||||||
"read_from_storage_dynamic" +
|
"read_from_storage_dynamic" +
|
||||||
@ -1429,6 +1431,7 @@ string YulUtilFunctions::writeToMemoryFunction(Type const& _type)
|
|||||||
|
|
||||||
string YulUtilFunctions::extractFromStorageValueDynamic(Type const& _type, bool _splitFunctionTypes)
|
string YulUtilFunctions::extractFromStorageValueDynamic(Type const& _type, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
|
if (_type.category() == Type::Category::Function)
|
||||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||||
|
|
||||||
string functionName =
|
string functionName =
|
||||||
@ -1474,6 +1477,7 @@ string YulUtilFunctions::extractFromStorageValue(Type const& _type, size_t _offs
|
|||||||
string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes)
|
string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
solAssert(_type.isValueType(), "");
|
solAssert(_type.isValueType(), "");
|
||||||
|
if (_type.category() == Type::Category::Function)
|
||||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||||
|
|
||||||
string functionName = string("cleanup_from_storage_") + (_splitFunctionTypes ? "split_" : "") + _type.identifier();
|
string functionName = string("cleanup_from_storage_") + (_splitFunctionTypes ? "split_" : "") + _type.identifier();
|
||||||
|
@ -268,65 +268,16 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
|||||||
string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
string functionName = IRNames::function(_varDecl);
|
string functionName = IRNames::function(_varDecl);
|
||||||
|
return m_context.functionCollector().createFunction(functionName, [&]() {
|
||||||
Type const* type = _varDecl.annotation().type;
|
Type const* type = _varDecl.annotation().type;
|
||||||
|
|
||||||
solAssert(_varDecl.isStateVariable(), "");
|
solAssert(_varDecl.isStateVariable(), "");
|
||||||
|
|
||||||
if (auto const* mappingType = dynamic_cast<MappingType const*>(type))
|
FunctionType accessorType(_varDecl);
|
||||||
return m_context.functionCollector().createFunction(functionName, [&]() {
|
TypePointers paramTypes = accessorType.parameterTypes();
|
||||||
solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), "");
|
|
||||||
pair<u256, unsigned> slot_offset = m_context.storageLocationOfVariable(_varDecl);
|
|
||||||
solAssert(slot_offset.second == 0, "");
|
|
||||||
FunctionType funType(_varDecl);
|
|
||||||
solUnimplementedAssert(funType.returnParameterTypes().size() == 1, "");
|
|
||||||
TypePointer returnType = funType.returnParameterTypes().front();
|
|
||||||
unsigned num_keys = 0;
|
|
||||||
stringstream indexAccesses;
|
|
||||||
string slot = m_context.newYulVariable();
|
|
||||||
do
|
|
||||||
{
|
|
||||||
solUnimplementedAssert(
|
|
||||||
mappingType->keyType()->sizeOnStack() == 1,
|
|
||||||
"Multi-slot mapping key unimplemented - might not be a problem"
|
|
||||||
);
|
|
||||||
indexAccesses <<
|
|
||||||
slot <<
|
|
||||||
" := " <<
|
|
||||||
m_utils.mappingIndexAccessFunction(*mappingType, *mappingType->keyType()) <<
|
|
||||||
"(" <<
|
|
||||||
slot;
|
|
||||||
if (mappingType->keyType()->sizeOnStack() > 0)
|
|
||||||
indexAccesses <<
|
|
||||||
", " <<
|
|
||||||
suffixedVariableNameList("key", num_keys, num_keys + mappingType->keyType()->sizeOnStack());
|
|
||||||
indexAccesses << ")\n";
|
|
||||||
num_keys += mappingType->keyType()->sizeOnStack();
|
|
||||||
}
|
|
||||||
while ((mappingType = dynamic_cast<MappingType const*>(mappingType->valueType())));
|
|
||||||
|
|
||||||
return Whiskers(R"(
|
|
||||||
function <functionName>(<keys>) -> rval {
|
|
||||||
let <slot> := <base>
|
|
||||||
<indexAccesses>
|
|
||||||
rval := <readStorage>(<slot>)
|
|
||||||
}
|
|
||||||
)")
|
|
||||||
("functionName", functionName)
|
|
||||||
("keys", suffixedVariableNameList("key", 0, num_keys))
|
|
||||||
("readStorage", m_utils.readFromStorage(*returnType, 0, false))
|
|
||||||
("indexAccesses", indexAccesses.str())
|
|
||||||
("slot", slot)
|
|
||||||
("base", slot_offset.first.str())
|
|
||||||
.render();
|
|
||||||
});
|
|
||||||
else
|
|
||||||
{
|
|
||||||
solUnimplementedAssert(type->isValueType(), "");
|
|
||||||
|
|
||||||
return m_context.functionCollector().createFunction(functionName, [&]() {
|
|
||||||
if (_varDecl.immutable())
|
if (_varDecl.immutable())
|
||||||
{
|
{
|
||||||
|
solAssert(paramTypes.empty(), "");
|
||||||
solUnimplementedAssert(type->sizeOnStack() == 1, "");
|
solUnimplementedAssert(type->sizeOnStack() == 1, "");
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>() -> rval {
|
function <functionName>() -> rval {
|
||||||
@ -338,6 +289,8 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
else if (_varDecl.isConstant())
|
else if (_varDecl.isConstant())
|
||||||
|
{
|
||||||
|
solAssert(paramTypes.empty(), "");
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>() -> <ret> {
|
function <functionName>() -> <ret> {
|
||||||
<ret> := <constantValueFunction>()
|
<ret> := <constantValueFunction>()
|
||||||
@ -347,23 +300,114 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
("constantValueFunction", IRGeneratorForStatements(m_context, m_utils).constantValueFunction(_varDecl))
|
("constantValueFunction", IRGeneratorForStatements(m_context, m_utils).constantValueFunction(_varDecl))
|
||||||
("ret", suffixedVariableNameList("ret_", 0, _varDecl.type()->sizeOnStack()))
|
("ret", suffixedVariableNameList("ret_", 0, _varDecl.type()->sizeOnStack()))
|
||||||
.render();
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
string code;
|
||||||
|
|
||||||
|
auto const& location = m_context.storageLocationOfVariable(_varDecl);
|
||||||
|
code += Whiskers(R"(
|
||||||
|
let slot := <slot>
|
||||||
|
let offset := <offset>
|
||||||
|
)")
|
||||||
|
("slot", location.first.str())
|
||||||
|
("offset", to_string(location.second))
|
||||||
|
.render();
|
||||||
|
|
||||||
|
if (!paramTypes.empty())
|
||||||
|
solAssert(
|
||||||
|
location.second == 0,
|
||||||
|
"If there are parameters, we are dealing with structs or mappings and thus should have offset zero."
|
||||||
|
);
|
||||||
|
|
||||||
|
// The code of an accessor is of the form `x[a][b][c]` (it is slightly more complicated
|
||||||
|
// if the final type is a struct).
|
||||||
|
// In each iteration of the loop below, we consume one parameter, perform an
|
||||||
|
// index access, reassign the yul variable `slot` and move @a currentType further "down".
|
||||||
|
// The initial value of @a currentType is only used if we skip the loop completely.
|
||||||
|
TypePointer currentType = _varDecl.annotation().type;
|
||||||
|
|
||||||
|
vector<string> parameters;
|
||||||
|
vector<string> returnVariables;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < paramTypes.size(); ++i)
|
||||||
|
{
|
||||||
|
MappingType const* mappingType = dynamic_cast<MappingType const*>(currentType);
|
||||||
|
ArrayType const* arrayType = dynamic_cast<ArrayType const*>(currentType);
|
||||||
|
solAssert(mappingType || arrayType, "");
|
||||||
|
|
||||||
|
vector<string> keys = IRVariable("key_" + to_string(i),
|
||||||
|
mappingType ? *mappingType->keyType() : *TypeProvider::uint256()
|
||||||
|
).stackSlots();
|
||||||
|
parameters += keys;
|
||||||
|
code += Whiskers(R"(
|
||||||
|
slot<?array>, offset</array> := <indexAccess>(slot<?+keys>, <keys></+keys>)
|
||||||
|
)")
|
||||||
|
(
|
||||||
|
"indexAccess",
|
||||||
|
mappingType ?
|
||||||
|
m_utils.mappingIndexAccessFunction(*mappingType, *mappingType->keyType()) :
|
||||||
|
m_utils.storageArrayIndexAccessFunction(*arrayType)
|
||||||
|
)
|
||||||
|
("array", arrayType != nullptr)
|
||||||
|
("keys", joinHumanReadable(keys))
|
||||||
|
.render();
|
||||||
|
|
||||||
|
currentType = mappingType ? mappingType->valueType() : arrayType->baseType();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto returnTypes = accessorType.returnParameterTypes();
|
||||||
|
solAssert(returnTypes.size() >= 1, "");
|
||||||
|
if (StructType const* structType = dynamic_cast<StructType const*>(currentType))
|
||||||
|
{
|
||||||
|
solAssert(location.second == 0, "");
|
||||||
|
auto const& names = accessorType.returnParameterNames();
|
||||||
|
for (size_t i = 0; i < names.size(); ++i)
|
||||||
|
{
|
||||||
|
if (returnTypes[i]->category() == Type::Category::Mapping)
|
||||||
|
continue;
|
||||||
|
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
|
||||||
|
if (!arrayType->isByteArray())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// TODO conversion from storage byte arrays is not yet implemented.
|
||||||
|
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
||||||
|
vector<string> retVars = IRVariable("ret_" + to_string(returnVariables.size()), *returnTypes[i]).stackSlots();
|
||||||
|
returnVariables += retVars;
|
||||||
|
code += Whiskers(R"(
|
||||||
|
<ret> := <readStorage>(add(slot, <slotOffset>))
|
||||||
|
)")
|
||||||
|
("ret", joinHumanReadable(retVars))
|
||||||
|
("readStorage", m_utils.readFromStorage(*returnTypes[i], offsets.second, true))
|
||||||
|
("slotOffset", offsets.first.str())
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pair<u256, unsigned> slot_offset = m_context.storageLocationOfVariable(_varDecl);
|
solAssert(returnTypes.size() == 1, "");
|
||||||
|
vector<string> retVars = IRVariable("ret", *returnTypes.front()).stackSlots();
|
||||||
|
returnVariables += retVars;
|
||||||
|
// TODO conversion from storage byte arrays is not yet implemented.
|
||||||
|
code += Whiskers(R"(
|
||||||
|
<ret> := <readStorage>(slot, offset)
|
||||||
|
)")
|
||||||
|
("ret", joinHumanReadable(retVars))
|
||||||
|
("readStorage", m_utils.readFromStorageDynamic(*returnTypes.front(), true))
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
function <functionName>() -> rval {
|
function <functionName>(<params>) -> <retVariables> {
|
||||||
rval := <readStorage>(<slot>)
|
<code>
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("readStorage", m_utils.readFromStorage(*type, slot_offset.second, false))
|
("params", joinHumanReadable(parameters))
|
||||||
("slot", slot_offset.first.str())
|
("retVariables", joinHumanReadable(returnVariables))
|
||||||
|
("code", std::move(code))
|
||||||
.render();
|
.render();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl)
|
string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
|
@ -1466,8 +1466,44 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
solAssert(false, "Unknown magic member.");
|
solAssert(false, "Unknown magic member.");
|
||||||
break;
|
break;
|
||||||
case Type::Category::Struct:
|
case Type::Category::Struct:
|
||||||
|
{
|
||||||
|
auto const& structType = dynamic_cast<StructType const&>(*_memberAccess.expression().annotation().type);
|
||||||
|
|
||||||
|
IRVariable expression(_memberAccess.expression());
|
||||||
|
switch (structType.location())
|
||||||
|
{
|
||||||
|
case DataLocation::Storage:
|
||||||
|
{
|
||||||
|
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
|
||||||
|
string slot = m_context.newYulVariable();
|
||||||
|
m_code << "let " << slot << " := " <<
|
||||||
|
("add(" + expression.name() + ", " + offsets.first.str() + ")\n");
|
||||||
|
setLValue(_memberAccess, IRLValue{
|
||||||
|
type(_memberAccess),
|
||||||
|
IRLValue::Storage{slot, offsets.second}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DataLocation::Memory:
|
||||||
|
{
|
||||||
|
string pos = m_context.newYulVariable();
|
||||||
|
m_code << "let " << pos << " := " <<
|
||||||
|
("add(" + expression.part("mpos").name() + ", " + structType.memoryOffsetOfMember(member).str() + ")\n");
|
||||||
|
setLValue(_memberAccess, IRLValue{
|
||||||
|
type(_memberAccess),
|
||||||
|
IRLValue::Memory{pos}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DataLocation::CallData:
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(false, "");
|
solUnimplementedAssert(false, "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
solAssert(false, "Illegal data location for struct.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Enum:
|
case Type::Category::Enum:
|
||||||
{
|
{
|
||||||
|
@ -1174,6 +1174,12 @@ bool CommandLineInterface::processInput()
|
|||||||
endl;
|
endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (targetMachine == Machine::Ewasm && inputLanguage != Input::StrictAssembly && inputLanguage != Input::Ewasm)
|
||||||
|
{
|
||||||
|
serr() << "The selected input language is not directly supported when targeting the Ewasm machine ";
|
||||||
|
serr() << "and automatic translation is not available." << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
serr() <<
|
serr() <<
|
||||||
"Warning: Yul is still experimental. Please use the output with care." <<
|
"Warning: Yul is still experimental. Please use the output with care." <<
|
||||||
endl;
|
endl;
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
--assemble --machine ewasm
|
@ -0,0 +1 @@
|
|||||||
|
The selected input language is not directly supported when targeting the Ewasm machine and automatic translation is not available.
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
sstore(0, 1)
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
|
@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
|
|||||||
// PushSubSize
|
// PushSubSize
|
||||||
auto sub = _assembly.appendSubroutine(_subAsmPtr);
|
auto sub = _assembly.appendSubroutine(_subAsmPtr);
|
||||||
// PushSub
|
// PushSub
|
||||||
_assembly.pushSubroutineOffset(size_t(sub.data()));
|
_assembly.pushSubroutineOffset(static_cast<size_t>(sub.data()));
|
||||||
// PushDeployTimeAddress
|
// PushDeployTimeAddress
|
||||||
_assembly.append(PushDeployTimeAddress);
|
_assembly.append(PushDeployTimeAddress);
|
||||||
// AssignImmutable.
|
// AssignImmutable.
|
||||||
@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(immutable)
|
|||||||
_assembly.appendImmutableAssignment("someOtherImmutable");
|
_assembly.appendImmutableAssignment("someOtherImmutable");
|
||||||
|
|
||||||
auto sub = _assembly.appendSubroutine(_subAsmPtr);
|
auto sub = _assembly.appendSubroutine(_subAsmPtr);
|
||||||
_assembly.pushSubroutineOffset(size_t(sub.data()));
|
_assembly.pushSubroutineOffset(static_cast<size_t>(sub.data()));
|
||||||
|
|
||||||
checkCompilation(_assembly);
|
checkCompilation(_assembly);
|
||||||
|
|
||||||
|
@ -1227,7 +1227,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
|||||||
sub->append(t4.pushTag());
|
sub->append(t4.pushTag());
|
||||||
sub->append(Instruction::JUMP);
|
sub->append(Instruction::JUMP);
|
||||||
|
|
||||||
size_t subId = size_t(main.appendSubroutine(sub).data());
|
size_t subId = static_cast<size_t>(main.appendSubroutine(sub).data());
|
||||||
main.append(t1.toSubAssemblyTag(subId));
|
main.append(t1.toSubAssemblyTag(subId));
|
||||||
main.append(t1.toSubAssemblyTag(subId));
|
main.append(t1.toSubAssemblyTag(subId));
|
||||||
main.append(u256(8));
|
main.append(u256(8));
|
||||||
@ -1281,7 +1281,7 @@ BOOST_AUTO_TEST_CASE(cse_remove_redundant_shift_masking)
|
|||||||
if (!solidity::test::CommonOptions::get().evmVersion().hasBitwiseShifting())
|
if (!solidity::test::CommonOptions::get().evmVersion().hasBitwiseShifting())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 1; i < 256; i++)
|
for (size_t i = 1; i < 256; i++)
|
||||||
{
|
{
|
||||||
checkCSE({
|
checkCSE({
|
||||||
u256(boost::multiprecision::pow(u256(2), i) - 1),
|
u256(boost::multiprecision::pow(u256(2), i) - 1),
|
||||||
@ -1309,7 +1309,7 @@ BOOST_AUTO_TEST_CASE(cse_remove_redundant_shift_masking)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that opt. does NOT trigger
|
// Check that opt. does NOT trigger
|
||||||
for (int i = 1; i < 255; i++)
|
for (size_t i = 1; i < 255; i++)
|
||||||
{
|
{
|
||||||
checkCSE({
|
checkCSE({
|
||||||
u256(boost::multiprecision::pow(u256(2), i) - 1),
|
u256(boost::multiprecision::pow(u256(2), i) - 1),
|
||||||
|
14
test/libsolidity/semanticTests/getters/arrays.sol
Normal file
14
test/libsolidity/semanticTests/getters/arrays.sol
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
contract C {
|
||||||
|
uint8[][2] public a;
|
||||||
|
constructor() public {
|
||||||
|
a[1].push(3);
|
||||||
|
a[1].push(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// a(uint256,uint256): 0, 0 -> FAILURE
|
||||||
|
// a(uint256,uint256): 1, 0 -> 3
|
||||||
|
// a(uint256,uint256): 1, 1 -> 4
|
||||||
|
// a(uint256,uint256): 2, 0 -> FAILURE
|
11
test/libsolidity/semanticTests/getters/mapping.sol
Normal file
11
test/libsolidity/semanticTests/getters/mapping.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
contract C {
|
||||||
|
mapping(uint => mapping(uint => uint)) public x;
|
||||||
|
constructor() public {
|
||||||
|
x[1][2] = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// x(uint256,uint256): 1, 2 -> 3
|
||||||
|
// x(uint256,uint256): 0, 0 -> 0
|
20
test/libsolidity/semanticTests/getters/mapping_to_struct.sol
Normal file
20
test/libsolidity/semanticTests/getters/mapping_to_struct.sol
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint8 a;
|
||||||
|
uint16 b;
|
||||||
|
uint128 c;
|
||||||
|
uint d;
|
||||||
|
}
|
||||||
|
mapping(uint => mapping(uint => S)) public x;
|
||||||
|
constructor() public {
|
||||||
|
x[1][2].a = 3;
|
||||||
|
x[1][2].b = 4;
|
||||||
|
x[1][2].c = 5;
|
||||||
|
x[1][2].d = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// x(uint256,uint256): 1, 2 -> 3, 4, 5, 6
|
||||||
|
// x(uint256,uint256): 0, 0 -> 0x00, 0x00, 0x00, 0x00
|
19
test/libsolidity/semanticTests/getters/small_types.sol
Normal file
19
test/libsolidity/semanticTests/getters/small_types.sol
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
contract C {
|
||||||
|
uint8 public a;
|
||||||
|
uint16 public b;
|
||||||
|
uint128 public c;
|
||||||
|
uint public d;
|
||||||
|
constructor() public {
|
||||||
|
a = 3;
|
||||||
|
b = 4;
|
||||||
|
c = 5;
|
||||||
|
d = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// a() -> 3
|
||||||
|
// b() -> 4
|
||||||
|
// c() -> 5
|
||||||
|
// d() -> 6
|
@ -8,6 +8,8 @@ contract test {
|
|||||||
dynamicData[2][2] = 8;
|
dynamicData[2][2] = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// data(uint256,uint256): 2, 2 -> 8
|
// data(uint256,uint256): 2, 2 -> 8
|
||||||
// data(uint256,uint256): 2, 8 -> FAILURE # NB: the original code contained a bug here #
|
// data(uint256,uint256): 2, 8 -> FAILURE # NB: the original code contained a bug here #
|
||||||
|
@ -8,5 +8,7 @@ contract test {
|
|||||||
data[7].d = true;
|
data[7].d = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// data(uint256): 7 -> 1, 2, true
|
// data(uint256): 7 -> 1, 2, true
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C1 {
|
||||||
|
function f() external pure returns(int) { return 42; }
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C is C1 {
|
||||||
|
int override f;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (96-110): Override can only be used with public state variables.
|
Loading…
Reference in New Issue
Block a user