Uppercase E exponent literal evades underscore validation check
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 21
Description
## Description
Solidity rejects an underscore placed directly against the exponent marker of a decimal number literal, but only when the exponent marker is lowercase `e`. The post-lex validator in `libsolidity/analysis/SyntaxChecker.cpp:342-346` searches the literal text for the fixed *lowercase* substrings `"e_"` and `"_e"`:
```cpp
// libsolidity/analysis/SyntaxChecker.cpp:342-346 (inside visit(Literal), decimal branch)
if (value.find("_e") != ASTString::npos)
m_errorReporter.syntaxError(6415_error, _literal.location(),
"Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed.");
if (value.find("e_") != ASTString::npos)
m_errorReporter.syntaxError(6165_error, _literal.location(),
"Invalid use of underscores in number literal. No underscore in front of exponent allowed.");
```
The scanner equally accepts uppercase `E` as an exponent marker (`liblangutil/Scanner.cpp:996`, `m_char == 'e' || m_char == 'E'`), and the AST keeps the literal's original case, so `"1E_5"` contains `"E_"` and never matches `"e_"` — `find` returns `npos` and no error is emitted. As a result, every uppercase-`E` malformed literal slips through: `1E_5` and `1_E5` are silently accepted as `100000` (underscore dropped), while the byte-identical lowercase `1e_5`/`1_e5` are hard compile errors 6165/6415.
Expected: the underscore-placement check should be case-insensitive so that `1E_5`/`1_E5` are rejected with the same errors (6165/6415) as their lowercase equivalents, instead of silently accepting a malformed literal with no diagnostic.
## Environment
- Compiler version: `47b9dedda`
## Steps to Reproduce
The following compiles without any diagnostic; the underscores are silently dropped:
```solidity
uint constant A = 1E_5; // accepted, == 100000 (lowercase 1e_5 => Error 6165)
uint constant B = 1_E5; // accepted, == 100000 (lowercase 1_e5 => Error 6415)
uint constant C = 3E_0; // accepted, == 3
```
For comparison, the byte-identical lowercase forms `1e_5` and `1_e5` are hard errors (6165 and 6415 respectively), demonstrating the case-sensitivity asymmetry.
Contributor guide
Assessment
This issue has not been assessed yet.