mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #8930 from ethereum/switch-single-default-warn
Warn on YUL switch statement with only default statement
This commit is contained in:
		
						commit
						bec9b24c5b
					
				| @ -4,6 +4,7 @@ Language Features: | ||||
| 
 | ||||
| 
 | ||||
| Compiler Features: | ||||
|  * Yul: Raise warning for switch statements that only have a default and no other cases. | ||||
| 
 | ||||
| 
 | ||||
| Bugfixes: | ||||
|  | ||||
| @ -359,6 +359,13 @@ void AsmAnalyzer::operator()(Switch const& _switch) | ||||
| { | ||||
| 	yulAssert(_switch.expression, ""); | ||||
| 
 | ||||
| 	if (_switch.cases.size() == 1 && !_switch.cases[0].value) | ||||
| 		m_errorReporter.warning( | ||||
| 			9592_error, | ||||
| 			_switch.location, | ||||
| 			"\"switch\" statement with only a default case." | ||||
| 		); | ||||
| 
 | ||||
| 	YulString valueType = expectExpression(*_switch.expression); | ||||
| 
 | ||||
| 	set<u256> cases; | ||||
|  | ||||
| @ -33,14 +33,14 @@ | ||||
|           { | ||||
|             "id": 4, | ||||
|             "nodeType": "Block", | ||||
|             "src": "42:48:1", | ||||
|             "src": "42:58:1", | ||||
|             "statements": | ||||
|             [ | ||||
|               { | ||||
|                 "AST": | ||||
|                 { | ||||
|                   "nodeType": "YulBlock", | ||||
|                   "src": "61:23:1", | ||||
|                   "src": "61:33:1", | ||||
|                   "statements": | ||||
|                   [ | ||||
|                     { | ||||
| @ -50,11 +50,29 @@ | ||||
|                           "body": | ||||
|                           { | ||||
|                             "nodeType": "YulBlock", | ||||
|                             "src": "80:2:1", | ||||
|                             "src": "79:2:1", | ||||
|                             "statements": [] | ||||
|                           }, | ||||
|                           "nodeType": "YulCase", | ||||
|                           "src": "72:10:1", | ||||
|                           "src": "72:9:1", | ||||
|                           "value": | ||||
|                           { | ||||
|                             "kind": "number", | ||||
|                             "nodeType": "YulLiteral", | ||||
|                             "src": "77:1:1", | ||||
|                             "type": "", | ||||
|                             "value": "0" | ||||
|                           } | ||||
|                         }, | ||||
|                         { | ||||
|                           "body": | ||||
|                           { | ||||
|                             "nodeType": "YulBlock", | ||||
|                             "src": "90:2:1", | ||||
|                             "statements": [] | ||||
|                           }, | ||||
|                           "nodeType": "YulCase", | ||||
|                           "src": "82:10:1", | ||||
|                           "value": "default" | ||||
|                         } | ||||
|                       ], | ||||
| @ -67,7 +85,7 @@ | ||||
|                         "value": "0" | ||||
|                       }, | ||||
|                       "nodeType": "YulSwitch", | ||||
|                       "src": "63:19:1" | ||||
|                       "src": "63:29:1" | ||||
|                     } | ||||
|                   ] | ||||
|                 }, | ||||
| @ -75,7 +93,7 @@ | ||||
|                 "externalReferences": [], | ||||
|                 "id": 3, | ||||
|                 "nodeType": "InlineAssembly", | ||||
|                 "src": "52:32:1" | ||||
|                 "src": "52:42:1" | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
| @ -103,15 +121,15 @@ | ||||
|             "src": "42:0:1" | ||||
|           }, | ||||
|           "scope": 6, | ||||
|           "src": "17:73:1", | ||||
|           "src": "17:83:1", | ||||
|           "stateMutability": "view", | ||||
|           "virtual": false, | ||||
|           "visibility": "public" | ||||
|         } | ||||
|       ], | ||||
|       "scope": 7, | ||||
|       "src": "0:92:1" | ||||
|       "src": "0:102:1" | ||||
|     } | ||||
|   ], | ||||
|   "src": "0:93:1" | ||||
|   "src": "0:103:1" | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| contract C { | ||||
|     function g() view public { | ||||
|         assembly { switch 0 default {} } | ||||
|         assembly { switch 0 case 0 {} default {} } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -95,30 +95,30 @@ | ||||
|                     [ | ||||
|                       null | ||||
|                     ], | ||||
|                     "operations": "{\n    switch 0\n    default { }\n}" | ||||
|                     "operations": "{\n    switch 0\n    case 0 { }\n    default { }\n}" | ||||
|                   }, | ||||
|                   "children": [], | ||||
|                   "id": 3, | ||||
|                   "name": "InlineAssembly", | ||||
|                   "src": "52:32:1" | ||||
|                   "src": "52:42:1" | ||||
|                 } | ||||
|               ], | ||||
|               "id": 4, | ||||
|               "name": "Block", | ||||
|               "src": "42:48:1" | ||||
|               "src": "42:58:1" | ||||
|             } | ||||
|           ], | ||||
|           "id": 5, | ||||
|           "name": "FunctionDefinition", | ||||
|           "src": "17:73:1" | ||||
|           "src": "17:83:1" | ||||
|         } | ||||
|       ], | ||||
|       "id": 6, | ||||
|       "name": "ContractDefinition", | ||||
|       "src": "0:92:1" | ||||
|       "src": "0:102:1" | ||||
|     } | ||||
|   ], | ||||
|   "id": 7, | ||||
|   "name": "SourceUnit", | ||||
|   "src": "0:93:1" | ||||
|   "src": "0:103:1" | ||||
| } | ||||
|  | ||||
| @ -314,9 +314,17 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case) | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(switch_invalid_expression) | ||||
| { | ||||
| 	CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal or identifier expected."); | ||||
| 	CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected '(' but got reserved keyword 'default'"); | ||||
| 	CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", TypeError, "Expected expression to evaluate to one value, but got 0 values instead."); | ||||
| 	CHECK_PARSE_ERROR("{ switch {} case 1 {} default {} }", ParserError, "Literal or identifier expected."); | ||||
| 	CHECK_PARSE_ERROR( | ||||
| 		"{ switch mload case 1 {} default {} }", | ||||
| 		ParserError, | ||||
| 		"Expected '(' but got reserved keyword 'case'" | ||||
| 	); | ||||
| 	CHECK_PARSE_ERROR( | ||||
| 		"{ switch mstore(1, 1) case 1 {} default {} }", | ||||
| 		TypeError, | ||||
| 		"Expected expression to evaluate to one value, but got 0 values instead." | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(switch_default_before_case) | ||||
|  | ||||
| @ -1,15 +1,7 @@ | ||||
| contract C { | ||||
|     struct S { bool f; } | ||||
|     S s; | ||||
|     function f(uint256 a) internal pure { | ||||
|         S storage c; | ||||
|         assembly { | ||||
|             switch a | ||||
|             default { c_slot := s_slot } | ||||
|         } | ||||
|         c; | ||||
|     } | ||||
|     function g(bool flag) internal pure { | ||||
|     function f(bool flag) internal pure { | ||||
|         S storage c; | ||||
|         assembly { | ||||
|             switch flag | ||||
| @ -18,7 +10,7 @@ contract C { | ||||
|         } | ||||
|         c; | ||||
|     } | ||||
|     function h(uint256 a) internal pure { | ||||
|     function g(uint256 a) internal pure { | ||||
|         S storage c; | ||||
|         assembly { | ||||
|             switch a | ||||
|  | ||||
| @ -1,20 +1,14 @@ | ||||
| contract C { | ||||
|     struct S { bool f; } | ||||
|     S s; | ||||
|     function f(uint256 a) internal pure returns (S storage c) { | ||||
|         assembly { | ||||
|             switch a | ||||
|             default { c_slot := s_slot } | ||||
|         } | ||||
|     } | ||||
|     function g(bool flag) internal pure returns (S storage c) { | ||||
|     function f(bool flag) internal pure returns (S storage c) { | ||||
|         assembly { | ||||
|             switch flag | ||||
|             case 0 { c_slot := s_slot } | ||||
|             default { c_slot := s_slot } | ||||
|         } | ||||
|     } | ||||
|     function h(uint256 a) internal pure returns (S storage c) { | ||||
|     function g(uint256 a) internal pure returns (S storage c) { | ||||
|         assembly { | ||||
|             switch a | ||||
|             case 0 { revert(0, 0) } | ||||
|  | ||||
| @ -0,0 +1,12 @@ | ||||
| contract C { | ||||
|     struct S { bool f; } | ||||
|     S s; | ||||
|     function f(uint256 a) internal pure returns (S storage c) { | ||||
|         assembly { | ||||
|             switch a | ||||
|                 default { c_slot := s_slot } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| // ---- | ||||
| // Warning: (142-195): "switch" statement with only a default case. | ||||
| @ -87,12 +87,12 @@ pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse( | ||||
| 	shared_ptr<Object> parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false); | ||||
| 	if (!parserResult) | ||||
| 		return {}; | ||||
| 	if (!parserResult->code || !errorReporter.errors().empty()) | ||||
| 	if (!parserResult->code || errorReporter.hasErrors()) | ||||
| 		return {}; | ||||
| 	shared_ptr<AsmAnalysisInfo> analysisInfo = make_shared<AsmAnalysisInfo>(); | ||||
| 	AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->dataNames()); | ||||
| 	// TODO this should be done recursively.
 | ||||
| 	if (!analyzer.analyze(*parserResult->code) || !errorReporter.errors().empty()) | ||||
| 	if (!analyzer.analyze(*parserResult->code) || errorReporter.hasErrors()) | ||||
| 		return {}; | ||||
| 	return {std::move(parserResult->code), std::move(analysisInfo)}; | ||||
| } | ||||
|  | ||||
| @ -332,7 +332,7 @@ BOOST_FIXTURE_TEST_CASE(if_statement_custom_weights, CustomWeightFixture) | ||||
| BOOST_AUTO_TEST_CASE(switch_statement_tiny) | ||||
| { | ||||
| 	BOOST_CHECK_EQUAL(codeSize( | ||||
| 		"{ switch calldatasize() default {} }" | ||||
| 		"{ switch calldatasize() case 0 {} }" | ||||
| 	), 4); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -362,7 +362,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c | ||||
| 	ErrorList errors; | ||||
| 	soltestAssert(m_dialect, ""); | ||||
| 	std::tie(m_ast, m_analysisInfo) = yul::test::parse(m_source, *m_dialect, errors); | ||||
| 	if (!m_ast || !m_analysisInfo || !errors.empty()) | ||||
| 	if (!m_ast || !m_analysisInfo || !Error::containsOnlyWarnings(errors)) | ||||
| 	{ | ||||
| 		AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; | ||||
| 		printErrors(_stream, errors); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user