diff --git a/Changelog.md b/Changelog.md index 0007fc0ce..495864c6e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,12 +1,12 @@ ### 0.8.1 (unreleased) Compiler Features: + * Parser: Report meaningful error if parsing a version pragma failed. * SMTChecker: Support ABI functions as uninterpreted functions. Bugfixes: * SMTChecker: Fix false negatives in overriding modifiers. - ### 0.8.0 (2020-12-16) Breaking Changes: diff --git a/liblangutil/SemVerHandler.cpp b/liblangutil/SemVerHandler.cpp index ee5490f55..0c09ea14d 100644 --- a/liblangutil/SemVerHandler.cpp +++ b/liblangutil/SemVerHandler.cpp @@ -147,7 +147,7 @@ bool SemVerMatchExpression::matches(SemVerVersion const& _version) const return false; } -SemVerMatchExpression SemVerMatchExpressionParser::parse() +optional SemVerMatchExpressionParser::parse() { reset(); @@ -166,6 +166,7 @@ SemVerMatchExpression SemVerMatchExpressionParser::parse() catch (SemVerError const&) { reset(); + return nullopt; } return m_expression; diff --git a/liblangutil/SemVerHandler.h b/liblangutil/SemVerHandler.h index 0a291224e..64b191154 100644 --- a/liblangutil/SemVerHandler.h +++ b/liblangutil/SemVerHandler.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -86,7 +87,9 @@ public: SemVerMatchExpressionParser(std::vector _tokens, std::vector _literals): m_tokens(std::move(_tokens)), m_literals(std::move(_literals)) {} - SemVerMatchExpression parse(); + + /// Returns an expression if it was parseable, or nothing otherwise. + std::optional parse(); private: void reset(); diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 9fac5f6d5..c85791449 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -160,8 +160,10 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) vector literals(_pragma.literals().begin() + 1, _pragma.literals().end()); SemVerMatchExpressionParser parser(tokens, literals); auto matchExpression = parser.parse(); + // An unparsable version pragma is an unrecoverable fatal error in the parser. + solAssert(matchExpression.has_value(), ""); static SemVerVersion const currentVersion{string(VersionString)}; - if (!matchExpression.matches(currentVersion)) + if (!matchExpression->matches(currentVersion)) m_errorReporter.syntaxError( 3997_error, _pragma.location(), diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index f68040a37..e755fd497 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -140,9 +140,16 @@ void Parser::parsePragmaVersion(SourceLocation const& _location, vector c { SemVerMatchExpressionParser parser(_tokens, _literals); auto matchExpression = parser.parse(); + if (!matchExpression.has_value()) + m_errorReporter.fatalParserError( + 1684_error, + _location, + "Found version pragma, but failed to parse it. " + "Please ensure there is a trailing semicolon." + ); static SemVerVersion const currentVersion{string(VersionString)}; // FIXME: only match for major version incompatibility - if (!matchExpression.matches(currentVersion)) + if (!matchExpression->matches(currentVersion)) // If m_parserErrorRecovery is true, the same message will appear from SyntaxChecker::visit(), // so we don't need to report anything here. if (!m_parserErrorRecovery) diff --git a/scripts/test_antlr_grammar.sh b/scripts/test_antlr_grammar.sh index 39c433028..360cc00d2 100755 --- a/scripts/test_antlr_grammar.sh +++ b/scripts/test_antlr_grammar.sh @@ -114,7 +114,7 @@ do SOL_FILES+=("$line") done < <( grep -riL -E \ - "^\/\/ (Syntax|Type|Declaration)Error|^\/\/ ParserError (2837|3716|3997|5333|6275|6281|6933|7319)|^==== Source:" \ + "^\/\/ (Syntax|Type|Declaration)Error|^\/\/ ParserError (1684|2837|3716|3997|5333|6275|6281|6933|7319)|^==== Source:" \ "${ROOT_DIR}/test/libsolidity/syntaxTests" \ "${ROOT_DIR}/test/libsolidity/semanticTests" | grep -v -E 'comments/.*_direction_override.*.sol' | diff --git a/test/libsolidity/SemVerMatcher.cpp b/test/libsolidity/SemVerMatcher.cpp index 5337c844a..7206bc251 100644 --- a/test/libsolidity/SemVerMatcher.cpp +++ b/test/libsolidity/SemVerMatcher.cpp @@ -58,11 +58,12 @@ SemVerMatchExpression parseExpression(string const& _input) } auto expression = SemVerMatchExpressionParser(tokens, literals).parse(); + BOOST_REQUIRE(expression.has_value()); BOOST_CHECK_MESSAGE( - expression.isValid(), + expression->isValid(), "Expression \"" + _input + "\" did not parse properly." ); - return expression; + return *expression; } } diff --git a/test/libsolidity/syntaxTests/pragma/broken_version_1.sol b/test/libsolidity/syntaxTests/pragma/broken_version_1.sol new file mode 100644 index 000000000..7b23fdfb5 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/broken_version_1.sol @@ -0,0 +1,3 @@ +pragma solidity ^0^1; +// ---- +// ParserError 5333: (0-21): Source file requires different compiler version (current compiler is .... diff --git a/test/libsolidity/syntaxTests/pragma/broken_version_2.sol b/test/libsolidity/syntaxTests/pragma/broken_version_2.sol new file mode 100644 index 000000000..903ac4cd3 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/broken_version_2.sol @@ -0,0 +1,3 @@ +pragma solidity pragma; +// ---- +// ParserError 1684: (0-23): Found version pragma, but failed to parse it. Please ensure there is a trailing semicolon. diff --git a/test/libsolidity/syntaxTests/pragma/broken_version_3.sol b/test/libsolidity/syntaxTests/pragma/broken_version_3.sol new file mode 100644 index 000000000..fd8a0f1a7 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/broken_version_3.sol @@ -0,0 +1,4 @@ +pragma solidity #8.0.0; +// ---- +// ParserError 6281: (16-17): Token incompatible with Solidity parser as part of pragma directive. +// ParserError 5333: (0-23): Source file requires different compiler version (current compiler is .... diff --git a/test/libsolidity/syntaxTests/pragma/broken_version_4.sol b/test/libsolidity/syntaxTests/pragma/broken_version_4.sol new file mode 100644 index 000000000..76560fac6 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/broken_version_4.sol @@ -0,0 +1,3 @@ +pragma solidity (8.0.0); +// ---- +// ParserError 1684: (0-24): Found version pragma, but failed to parse it. Please ensure there is a trailing semicolon. diff --git a/test/libsolidity/syntaxTests/pragma/broken_version_5.sol b/test/libsolidity/syntaxTests/pragma/broken_version_5.sol new file mode 100644 index 000000000..3c284be74 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/broken_version_5.sol @@ -0,0 +1,3 @@ +pragma solidity 88_; +// ---- +// ParserError 1684: (0-20): Found version pragma, but failed to parse it. Please ensure there is a trailing semicolon. diff --git a/test/libsolidity/syntaxTests/pragma/unterminated_pragma.sol b/test/libsolidity/syntaxTests/pragma/unterminated_pragma.sol new file mode 100644 index 000000000..8c7337bb5 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/unterminated_pragma.sol @@ -0,0 +1,3 @@ +pragma solidity 0.4.3 +// ---- +// ParserError 2314: (22-22): Expected ';' but got end of source diff --git a/test/libsolidity/syntaxTests/pragma/unterminated_version.sol b/test/libsolidity/syntaxTests/pragma/unterminated_version.sol new file mode 100644 index 000000000..6dc7373c0 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/unterminated_version.sol @@ -0,0 +1,4 @@ +pragma solidity 0.4.3 +pragma abicoder v2; +// ---- +// ParserError 1684: (0-41): Found version pragma, but failed to parse it. Please ensure there is a trailing semicolon.