Skip to content

Commit 77c40cd

Browse files
authored
Merge pull request ethereum#12740 from ethereum/remove-locale-dependent-operations
Replace all locale-dependent operations with locale-agnostic counterparts
2 parents 57e012d + 52dfccc commit 77c40cd

File tree

16 files changed

+105
-51
lines changed

16 files changed

+105
-51
lines changed

libevmasm/AssemblyItem.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,7 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
200200
case Operation:
201201
{
202202
assertThrow(isValidInstruction(instruction()), AssemblyException, "Invalid instruction.");
203-
string name = instructionInfo(instruction()).name;
204-
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
205-
text = name;
203+
text = util::toLower(instructionInfo(instruction()).name);
206204
break;
207205
}
208206
case Push:

liblangutil/Token.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@
4040
// You should have received a copy of the GNU General Public License
4141
// along with solidity. If not, see <http://www.gnu.org/licenses/>.
4242

43-
#include <liblangutil/Token.h>
4443
#include <liblangutil/Exceptions.h>
44+
#include <liblangutil/Token.h>
45+
#include <libsolutil/StringUtils.h>
46+
4547
#include <map>
4648

49+
4750
using namespace std;
4851

4952
namespace solidity::langutil
@@ -180,11 +183,11 @@ tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(string const& _
180183
return ret;
181184
};
182185

183-
auto positionM = find_if(_literal.begin(), _literal.end(), ::isdigit);
186+
auto positionM = find_if(_literal.begin(), _literal.end(), util::isDigit);
184187
if (positionM != _literal.end())
185188
{
186189
string baseType(_literal.begin(), positionM);
187-
auto positionX = find_if_not(positionM, _literal.end(), ::isdigit);
190+
auto positionX = find_if_not(positionM, _literal.end(), util::isDigit);
188191
int m = parseSize(positionM, positionX);
189192
Token keyword = keywordByName(baseType);
190193
if (keyword == Token::Bytes)
@@ -208,7 +211,7 @@ tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(string const& _
208211
positionM < positionX &&
209212
positionX < _literal.end() &&
210213
*positionX == 'x' &&
211-
all_of(positionX + 1, _literal.end(), ::isdigit)
214+
all_of(positionX + 1, _literal.end(), util::isDigit)
212215
) {
213216
int n = parseSize(positionX + 1, _literal.end());
214217
if (

libsolidity/ast/Types.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <libsolutil/CommonIO.h>
3434
#include <libsolutil/FunctionSelector.h>
3535
#include <libsolutil/Keccak256.h>
36+
#include <libsolutil/StringUtils.h>
3637
#include <libsolutil/UTF8.h>
3738

3839
#include <boost/algorithm/string.hpp>
@@ -781,8 +782,8 @@ tuple<bool, rational> RationalNumberType::parseRational(string const& _value)
781782
if (radixPoint != _value.end())
782783
{
783784
if (
784-
!all_of(radixPoint + 1, _value.end(), ::isdigit) ||
785-
!all_of(_value.begin(), radixPoint, ::isdigit)
785+
!all_of(radixPoint + 1, _value.end(), util::isDigit) ||
786+
!all_of(_value.begin(), radixPoint, util::isDigit)
786787
)
787788
return make_tuple(false, rational(0));
788789

libsolidity/codegen/ir/IRGeneratorForStatements.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ struct CopyTranslate: public yul::ASTCopier
203203
else
204204
solAssert(false);
205205

206-
if (isdigit(value.front()))
206+
if (isDigit(value.front()))
207207
return yul::Literal{_identifier.debugData, yul::LiteralKind::Number, yul::YulString{value}, {}};
208208
else
209209
return yul::Identifier{_identifier.debugData, yul::YulString{value}};

libsolidity/formal/CHC.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <libsmtutil/CHCSmtLib2Interface.h>
3434
#include <liblangutil/CharStreamProvider.h>
3535
#include <libsolutil/Algorithms.h>
36+
#include <libsolutil/StringUtils.h>
3637

3738
#ifdef HAVE_Z3_DLOPEN
3839
#include <z3_version.h>
@@ -1998,9 +1999,9 @@ map<unsigned, vector<unsigned>> CHC::summaryCalls(CHCSolverInterface::CexGraph c
19981999
// Predicates that do not have a CALLID have a predicate id at the end of <suffix>,
19992000
// so the assertion below should still hold.
20002001
auto beg = _s.data();
2001-
while (beg != _s.data() + _s.size() && !isdigit(*beg)) ++beg;
2002+
while (beg != _s.data() + _s.size() && !isDigit(*beg)) ++beg;
20022003
auto end = beg;
2003-
while (end != _s.data() + _s.size() && isdigit(*end)) ++end;
2004+
while (end != _s.data() + _s.size() && isDigit(*end)) ++end;
20042005

20052006
solAssert(beg != end, "Expected to find numerical call or predicate id.");
20062007

libsolutil/CommonData.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
* @date 2014
2121
*/
2222

23+
#include <libsolutil/Assertions.h>
2324
#include <libsolutil/CommonData.h>
2425
#include <libsolutil/Exceptions.h>
25-
#include <libsolutil/Assertions.h>
26-
#include <libsolutil/Keccak256.h>
2726
#include <libsolutil/FixedHash.h>
27+
#include <libsolutil/Keccak256.h>
28+
#include <libsolutil/StringUtils.h>
2829

2930
#include <boost/algorithm/string.hpp>
3031

@@ -154,9 +155,9 @@ string solidity::util::getChecksummedAddress(string const& _addr)
154155
char addressCharacter = s[i];
155156
uint8_t nibble = hash[i / 2u] >> (4u * (1u - (i % 2u))) & 0xf;
156157
if (nibble >= 8)
157-
ret += static_cast<char>(toupper(addressCharacter));
158+
ret += toUpper(addressCharacter);
158159
else
159-
ret += static_cast<char>(tolower(addressCharacter));
160+
ret += toLower(addressCharacter);
160161
}
161162
return ret;
162163
}
@@ -211,7 +212,7 @@ string solidity::util::escapeAndQuoteString(string const& _input)
211212
out += "\\r";
212213
else if (c == '\t')
213214
out += "\\t";
214-
else if (!isprint(c, locale::classic()))
215+
else if (!isPrint(c))
215216
{
216217
ostringstream o;
217218
o << "\\x" << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c);

libsolutil/StringUtils.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
#include <libsolutil/CommonData.h>
2828
#include <libsolutil/Numeric.h>
2929

30+
#include <algorithm>
3031
#include <limits>
32+
#include <locale>
3133
#include <string>
3234
#include <vector>
3335

@@ -197,4 +199,47 @@ inline std::optional<unsigned> toUnsignedInt(std::string const& _value)
197199
}
198200
}
199201

202+
/// Converts parameter _c to its lowercase equivalent if c is an uppercase letter and has a lowercase equivalent. It uses the classic "C" locale semantics.
203+
/// @param _c value to be converted
204+
/// @return the converted value
205+
inline char toLower(char _c)
206+
{
207+
return tolower(_c, std::locale::classic());
208+
}
209+
210+
/// Converts parameter _c to its uppercase equivalent if c is an lowercase letter and has a uppercase equivalent. It uses the classic "C" locale semantics.
211+
/// @param _c value to be converted
212+
/// @return the converted value
213+
inline char toUpper(char _c)
214+
{
215+
return toupper(_c, std::locale::classic());
216+
}
217+
218+
/// Converts parameter _s to its lowercase equivalent. It uses the classic "C" locale semantics.
219+
/// @param _s value to be converted
220+
/// @return the converted value
221+
inline std::string toLower(std::string _s)
222+
{
223+
std::transform(_s.begin(), _s.end(), _s.begin(), [](char _c) {
224+
return toLower(_c);
225+
});
226+
return _s;
227+
}
228+
229+
/// Checks whether _c is a decimal digit character. It uses the classic "C" locale semantics.
230+
/// @param _c character to be checked
231+
/// @return true if _c is a decimal digit character, false otherwise
232+
inline bool isDigit(char _c)
233+
{
234+
return isdigit(_c, std::locale::classic());
235+
}
236+
237+
// Checks if character is printable using classic "C" locale
238+
/// @param _c character to be checked
239+
/// @return true if _c is a printable character, false otherwise.
240+
inline bool isPrint(char _c)
241+
{
242+
return isprint(_c, std::locale::classic());
243+
}
244+
200245
}

libyul/backends/evm/EVMDialect.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@
2121

2222
#include <libyul/backends/evm/EVMDialect.h>
2323

24-
#include <libyul/AsmAnalysisInfo.h>
24+
#include <libevmasm/Instruction.h>
25+
#include <libevmasm/SemanticInformation.h>
26+
#include <liblangutil/Exceptions.h>
27+
#include <libsolutil/StringUtils.h>
2528
#include <libyul/AST.h>
26-
#include <libyul/Object.h>
27-
#include <libyul/Exceptions.h>
29+
#include <libyul/AsmAnalysisInfo.h>
2830
#include <libyul/AsmParser.h>
31+
#include <libyul/Exceptions.h>
32+
#include <libyul/Object.h>
2933
#include <libyul/Utilities.h>
3034
#include <libyul/backends/evm/AbstractAssembly.h>
31-
#include <libevmasm/SemanticInformation.h>
32-
#include <libevmasm/Instruction.h>
33-
34-
#include <liblangutil/Exceptions.h>
3535

3636
#include <range/v3/view/reverse.hpp>
3737
#include <range/v3/view/tail.hpp>
@@ -121,8 +121,7 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
121121
set<YulString> reserved;
122122
for (auto const& instr: evmasm::c_instructions)
123123
{
124-
string name = instr.first;
125-
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
124+
string name = toLower(instr.first);
126125
if (!baseFeeException(instr.second))
127126
reserved.emplace(name);
128127
}
@@ -142,8 +141,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
142141
map<YulString, BuiltinFunctionForEVM> builtins;
143142
for (auto const& instr: evmasm::c_instructions)
144143
{
145-
string name = instr.first;
146-
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
144+
string name = toLower(instr.first);
147145
auto const opcode = instr.second;
148146

149147
if (

libyul/optimiser/SimplificationRules.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@
2121

2222
#include <libyul/optimiser/SimplificationRules.h>
2323

24+
#include <libyul/AST.h>
25+
#include <libyul/Utilities.h>
26+
#include <libyul/backends/evm/EVMDialect.h>
2427
#include <libyul/optimiser/ASTCopier.h>
28+
#include <libyul/optimiser/DataFlowAnalyzer.h>
2529
#include <libyul/optimiser/Semantics.h>
2630
#include <libyul/optimiser/SyntacticalEquality.h>
27-
#include <libyul/optimiser/DataFlowAnalyzer.h>
28-
#include <libyul/backends/evm/EVMDialect.h>
29-
#include <libyul/AST.h>
30-
#include <libyul/Utilities.h>
3131

3232
#include <libevmasm/RuleList.h>
33+
#include <libsolutil/StringUtils.h>
3334

3435
using namespace std;
3536
using namespace solidity;
@@ -249,8 +250,7 @@ Expression Pattern::toExpression(shared_ptr<DebugData const> const& _debugData)
249250
for (auto const& arg: m_arguments)
250251
arguments.emplace_back(arg.toExpression(_debugData));
251252

252-
string name = instructionInfo(m_instruction).name;
253-
transform(begin(name), end(name), begin(name), [](auto _c) { return tolower(_c); });
253+
string name = util::toLower(instructionInfo(m_instruction).name);
254254

255255
return FunctionCall{_debugData,
256256
Identifier{_debugData, YulString{name}},

test/CommonSyntaxTest.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
using namespace std;
3131
using namespace solidity;
32-
using namespace solidity::util;
3332
using namespace solidity::util::formatting;
3433
using namespace solidity::langutil;
3534
using namespace solidity::frontend;
@@ -43,10 +42,11 @@ namespace
4342

4443
int parseUnsignedInteger(string::iterator& _it, string::iterator _end)
4544
{
46-
if (_it == _end || !isdigit(*_it))
45+
auto isDigit = [](char _c) -> bool {return isdigit(_c, std::locale::classic());};
46+
if (_it == _end || !isDigit(*_it))
4747
BOOST_THROW_EXCEPTION(runtime_error("Invalid test expectation. Source location expected."));
4848
int result = 0;
49-
while (_it != _end && isdigit(*_it))
49+
while (_it != _end && isDigit(*_it))
5050
{
5151
result *= 10;
5252
result += *_it - '0';
@@ -195,6 +195,7 @@ string CommonSyntaxTest::errorMessage(Exception const& _e)
195195

196196
vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(istream& _stream)
197197
{
198+
auto isDigit = [](char _c) -> bool {return isdigit(_c, std::locale::classic());};
198199
vector<SyntaxTestError> expectations;
199200
string line;
200201
while (getline(_stream, line))
@@ -207,14 +208,14 @@ vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(istream& _stream)
207208
if (it == line.end()) continue;
208209

209210
auto typeBegin = it;
210-
while (it != line.end() && isalpha(*it))
211+
while (it != line.end() && isalpha(*it, locale::classic()))
211212
++it;
212213
string errorType(typeBegin, it);
213214

214215
skipWhitespace(it, line.end());
215216

216217
optional<ErrorId> errorId;
217-
if (it != line.end() && isdigit(*it))
218+
if (it != line.end() && isDigit(*it))
218219
errorId = ErrorId{static_cast<unsigned long long>(parseUnsignedInteger(it, line.end()))};
219220

220221
expect(it, line.end(), ':');
@@ -227,7 +228,7 @@ vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(istream& _stream)
227228
if (it != line.end() && *it == '(')
228229
{
229230
++it;
230-
if (it != line.end() && !isdigit(*it))
231+
if (it != line.end() && !isDigit(*it))
231232
{
232233
auto sourceNameStart = it;
233234
while (it != line.end() && *it != ':')

0 commit comments

Comments
 (0)