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: | Compiler Features: | ||||||
|  |  * Yul: Raise warning for switch statements that only have a default and no other cases. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Bugfixes: | Bugfixes: | ||||||
|  | |||||||
| @ -359,6 +359,13 @@ void AsmAnalyzer::operator()(Switch const& _switch) | |||||||
| { | { | ||||||
| 	yulAssert(_switch.expression, ""); | 	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); | 	YulString valueType = expectExpression(*_switch.expression); | ||||||
| 
 | 
 | ||||||
| 	set<u256> cases; | 	set<u256> cases; | ||||||
|  | |||||||
| @ -33,14 +33,14 @@ | |||||||
|           { |           { | ||||||
|             "id": 4, |             "id": 4, | ||||||
|             "nodeType": "Block", |             "nodeType": "Block", | ||||||
|             "src": "42:48:1", |             "src": "42:58:1", | ||||||
|             "statements": |             "statements": | ||||||
|             [ |             [ | ||||||
|               { |               { | ||||||
|                 "AST": |                 "AST": | ||||||
|                 { |                 { | ||||||
|                   "nodeType": "YulBlock", |                   "nodeType": "YulBlock", | ||||||
|                   "src": "61:23:1", |                   "src": "61:33:1", | ||||||
|                   "statements": |                   "statements": | ||||||
|                   [ |                   [ | ||||||
|                     { |                     { | ||||||
| @ -50,11 +50,29 @@ | |||||||
|                           "body": |                           "body": | ||||||
|                           { |                           { | ||||||
|                             "nodeType": "YulBlock", |                             "nodeType": "YulBlock", | ||||||
|                             "src": "80:2:1", |                             "src": "79:2:1", | ||||||
|                             "statements": [] |                             "statements": [] | ||||||
|                           }, |                           }, | ||||||
|                           "nodeType": "YulCase", |                           "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" |                           "value": "default" | ||||||
|                         } |                         } | ||||||
|                       ], |                       ], | ||||||
| @ -67,7 +85,7 @@ | |||||||
|                         "value": "0" |                         "value": "0" | ||||||
|                       }, |                       }, | ||||||
|                       "nodeType": "YulSwitch", |                       "nodeType": "YulSwitch", | ||||||
|                       "src": "63:19:1" |                       "src": "63:29:1" | ||||||
|                     } |                     } | ||||||
|                   ] |                   ] | ||||||
|                 }, |                 }, | ||||||
| @ -75,7 +93,7 @@ | |||||||
|                 "externalReferences": [], |                 "externalReferences": [], | ||||||
|                 "id": 3, |                 "id": 3, | ||||||
|                 "nodeType": "InlineAssembly", |                 "nodeType": "InlineAssembly", | ||||||
|                 "src": "52:32:1" |                 "src": "52:42:1" | ||||||
|               } |               } | ||||||
|             ] |             ] | ||||||
|           }, |           }, | ||||||
| @ -103,15 +121,15 @@ | |||||||
|             "src": "42:0:1" |             "src": "42:0:1" | ||||||
|           }, |           }, | ||||||
|           "scope": 6, |           "scope": 6, | ||||||
|           "src": "17:73:1", |           "src": "17:83:1", | ||||||
|           "stateMutability": "view", |           "stateMutability": "view", | ||||||
|           "virtual": false, |           "virtual": false, | ||||||
|           "visibility": "public" |           "visibility": "public" | ||||||
|         } |         } | ||||||
|       ], |       ], | ||||||
|       "scope": 7, |       "scope": 7, | ||||||
|       "src": "0:92:1" |       "src": "0:102:1" | ||||||
|     } |     } | ||||||
|   ], |   ], | ||||||
|   "src": "0:93:1" |   "src": "0:103:1" | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| contract C { | contract C { | ||||||
|     function g() view public { |     function g() view public { | ||||||
|         assembly { switch 0 default {} } |         assembly { switch 0 case 0 {} default {} } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -95,30 +95,30 @@ | |||||||
|                     [ |                     [ | ||||||
|                       null |                       null | ||||||
|                     ], |                     ], | ||||||
|                     "operations": "{\n    switch 0\n    default { }\n}" |                     "operations": "{\n    switch 0\n    case 0 { }\n    default { }\n}" | ||||||
|                   }, |                   }, | ||||||
|                   "children": [], |                   "children": [], | ||||||
|                   "id": 3, |                   "id": 3, | ||||||
|                   "name": "InlineAssembly", |                   "name": "InlineAssembly", | ||||||
|                   "src": "52:32:1" |                   "src": "52:42:1" | ||||||
|                 } |                 } | ||||||
|               ], |               ], | ||||||
|               "id": 4, |               "id": 4, | ||||||
|               "name": "Block", |               "name": "Block", | ||||||
|               "src": "42:48:1" |               "src": "42:58:1" | ||||||
|             } |             } | ||||||
|           ], |           ], | ||||||
|           "id": 5, |           "id": 5, | ||||||
|           "name": "FunctionDefinition", |           "name": "FunctionDefinition", | ||||||
|           "src": "17:73:1" |           "src": "17:83:1" | ||||||
|         } |         } | ||||||
|       ], |       ], | ||||||
|       "id": 6, |       "id": 6, | ||||||
|       "name": "ContractDefinition", |       "name": "ContractDefinition", | ||||||
|       "src": "0:92:1" |       "src": "0:102:1" | ||||||
|     } |     } | ||||||
|   ], |   ], | ||||||
|   "id": 7, |   "id": 7, | ||||||
|   "name": "SourceUnit", |   "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) | BOOST_AUTO_TEST_CASE(switch_invalid_expression) | ||||||
| { | { | ||||||
| 	CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal or identifier expected."); | 	CHECK_PARSE_ERROR("{ switch {} case 1 {} default {} }", ParserError, "Literal or identifier expected."); | ||||||
| 	CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected '(' but got reserved keyword 'default'"); | 	CHECK_PARSE_ERROR( | ||||||
| 	CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", TypeError, "Expected expression to evaluate to one value, but got 0 values instead."); | 		"{ 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) | BOOST_AUTO_TEST_CASE(switch_default_before_case) | ||||||
|  | |||||||
| @ -1,15 +1,7 @@ | |||||||
| contract C { | contract C { | ||||||
|     struct S { bool f; } |     struct S { bool f; } | ||||||
|     S s; |     S s; | ||||||
|     function f(uint256 a) internal pure { |     function f(bool flag) internal pure { | ||||||
|         S storage c; |  | ||||||
|         assembly { |  | ||||||
|             switch a |  | ||||||
|             default { c_slot := s_slot } |  | ||||||
|         } |  | ||||||
|         c; |  | ||||||
|     } |  | ||||||
|     function g(bool flag) internal pure { |  | ||||||
|         S storage c; |         S storage c; | ||||||
|         assembly { |         assembly { | ||||||
|             switch flag |             switch flag | ||||||
| @ -18,7 +10,7 @@ contract C { | |||||||
|         } |         } | ||||||
|         c; |         c; | ||||||
|     } |     } | ||||||
|     function h(uint256 a) internal pure { |     function g(uint256 a) internal pure { | ||||||
|         S storage c; |         S storage c; | ||||||
|         assembly { |         assembly { | ||||||
|             switch a |             switch a | ||||||
|  | |||||||
| @ -1,20 +1,14 @@ | |||||||
| contract C { | contract C { | ||||||
|     struct S { bool f; } |     struct S { bool f; } | ||||||
|     S s; |     S s; | ||||||
|     function f(uint256 a) internal pure returns (S storage c) { |     function f(bool flag) internal pure returns (S storage c) { | ||||||
|         assembly { |  | ||||||
|             switch a |  | ||||||
|             default { c_slot := s_slot } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     function g(bool flag) internal pure returns (S storage c) { |  | ||||||
|         assembly { |         assembly { | ||||||
|             switch flag |             switch flag | ||||||
|             case 0 { c_slot := s_slot } |             case 0 { c_slot := s_slot } | ||||||
|             default { 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 { |         assembly { | ||||||
|             switch a |             switch a | ||||||
|             case 0 { revert(0, 0) } |             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); | 	shared_ptr<Object> parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false); | ||||||
| 	if (!parserResult) | 	if (!parserResult) | ||||||
| 		return {}; | 		return {}; | ||||||
| 	if (!parserResult->code || !errorReporter.errors().empty()) | 	if (!parserResult->code || errorReporter.hasErrors()) | ||||||
| 		return {}; | 		return {}; | ||||||
| 	shared_ptr<AsmAnalysisInfo> analysisInfo = make_shared<AsmAnalysisInfo>(); | 	shared_ptr<AsmAnalysisInfo> analysisInfo = make_shared<AsmAnalysisInfo>(); | ||||||
| 	AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->dataNames()); | 	AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->dataNames()); | ||||||
| 	// TODO this should be done recursively.
 | 	// TODO this should be done recursively.
 | ||||||
| 	if (!analyzer.analyze(*parserResult->code) || !errorReporter.errors().empty()) | 	if (!analyzer.analyze(*parserResult->code) || errorReporter.hasErrors()) | ||||||
| 		return {}; | 		return {}; | ||||||
| 	return {std::move(parserResult->code), std::move(analysisInfo)}; | 	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_AUTO_TEST_CASE(switch_statement_tiny) | ||||||
| { | { | ||||||
| 	BOOST_CHECK_EQUAL(codeSize( | 	BOOST_CHECK_EQUAL(codeSize( | ||||||
| 		"{ switch calldatasize() default {} }" | 		"{ switch calldatasize() case 0 {} }" | ||||||
| 	), 4); | 	), 4); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -362,7 +362,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c | |||||||
| 	ErrorList errors; | 	ErrorList errors; | ||||||
| 	soltestAssert(m_dialect, ""); | 	soltestAssert(m_dialect, ""); | ||||||
| 	std::tie(m_ast, m_analysisInfo) = yul::test::parse(m_source, *m_dialect, errors); | 	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; | 		AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; | ||||||
| 		printErrors(_stream, errors); | 		printErrors(_stream, errors); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user