mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	Patch #1346214: correctly optimize away "if 0"-style stmts
(thanks to Neal for review)
This commit is contained in:
		
							parent
							
								
									9f16760666
								
							
						
					
					
						commit
						ddbaa660d3
					
				
					 5 changed files with 57 additions and 18 deletions
				
			
		|  | @ -39,6 +39,8 @@ typedef struct _symtable_entry { | |||
| 	unsigned ste_generator : 1;   /* true if namespace is a generator */ | ||||
| 	unsigned ste_varargs : 1;     /* true if block has varargs */ | ||||
| 	unsigned ste_varkeywords : 1; /* true if block has varkeywords */ | ||||
| 	unsigned ste_returns_value : 1;  /* true if namespace uses return with
 | ||||
| 	                                    an argument */ | ||||
| 	int ste_lineno;          /* first line of block */ | ||||
| 	int ste_opt_lineno;      /* lineno of last exec or import * */ | ||||
| 	int ste_tmpname;         /* counter for listcomp temp vars */ | ||||
|  |  | |||
|  | @ -733,7 +733,7 @@ | |||
| ...     yield 1 | ||||
| Traceback (most recent call last): | ||||
|   .. | ||||
| SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[0]>, line 2) | ||||
| SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[0]>, line 3) | ||||
| 
 | ||||
| >>> def f(): | ||||
| ...     yield 1 | ||||
|  | @ -876,9 +876,9 @@ | |||
| ...         if 0: | ||||
| ...             return 3        # but *this* sucks (line 8) | ||||
| ...     if 0: | ||||
| ...         yield 2             # because it's a generator | ||||
| ...         yield 2             # because it's a generator (line 10) | ||||
| Traceback (most recent call last): | ||||
| SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[24]>, line 8) | ||||
| SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[24]>, line 10) | ||||
| 
 | ||||
| This one caused a crash (see SF bug 567538): | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,9 @@ What's New in Python 2.5 beta 1? | |||
| Core and builtins | ||||
| ----------------- | ||||
| 
 | ||||
| - Patch #1346214: Statements like "if 0: suite" are now again optimized | ||||
|   away like they were in Python 2.4. | ||||
| 
 | ||||
| - Builtin exceptions are now full-blown new-style classes instead of | ||||
|   instances pretending to be classes, which speeds up exception handling | ||||
|   by about 80% in comparison to 2.5a2. | ||||
|  |  | |||
|  | @ -2148,7 +2148,7 @@ static int | |||
| compiler_if(struct compiler *c, stmt_ty s) | ||||
| { | ||||
| 	basicblock *end, *next; | ||||
| 
 | ||||
| 	int constant; | ||||
| 	assert(s->kind == If_kind); | ||||
| 	end = compiler_new_block(c); | ||||
| 	if (end == NULL) | ||||
|  | @ -2156,6 +2156,17 @@ compiler_if(struct compiler *c, stmt_ty s) | |||
| 	next = compiler_new_block(c); | ||||
| 	if (next == NULL) | ||||
| 	    return 0; | ||||
| 	 | ||||
| 	constant = expr_constant(s->v.If.test); | ||||
| 	/* constant = 0: "if 0"
 | ||||
| 	 * constant = 1: "if 1", "if 2", ... | ||||
| 	 * constant = -1: rest */ | ||||
| 	if (constant == 0) { | ||||
| 		if (s->v.If.orelse) | ||||
| 			VISIT_SEQ(c, stmt, s->v.If.orelse); | ||||
| 	} else if (constant == 1) { | ||||
| 		VISIT_SEQ(c, stmt, s->v.If.body); | ||||
| 	} else { | ||||
| 		VISIT(c, expr, s->v.If.test); | ||||
| 		ADDOP_JREL(c, JUMP_IF_FALSE, next); | ||||
| 		ADDOP(c, POP_TOP); | ||||
|  | @ -2165,6 +2176,7 @@ compiler_if(struct compiler *c, stmt_ty s) | |||
| 		ADDOP(c, POP_TOP); | ||||
| 		if (s->v.If.orelse) | ||||
| 	    		VISIT_SEQ(c, stmt, s->v.If.orelse); | ||||
| 	} | ||||
| 	compiler_use_next_block(c, end); | ||||
| 	return 1; | ||||
| } | ||||
|  | @ -2639,10 +2651,6 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) | |||
| 		if (c->u->u_ste->ste_type != FunctionBlock) | ||||
| 			return compiler_error(c, "'return' outside function"); | ||||
| 		if (s->v.Return.value) { | ||||
| 			if (c->u->u_ste->ste_generator) { | ||||
| 				return compiler_error(c, | ||||
| 				    "'return' with argument inside generator"); | ||||
| 			} | ||||
| 			VISIT(c, expr, s->v.Return.value); | ||||
| 		} | ||||
| 		else | ||||
|  | @ -3356,6 +3364,13 @@ expr_constant(expr_ty e) | |||
| 		return PyObject_IsTrue(e->v.Num.n); | ||||
| 	case Str_kind: | ||||
| 		return PyObject_IsTrue(e->v.Str.s); | ||||
| 	case Name_kind: | ||||
| 		/* __debug__ is not assignable, so we can optimize
 | ||||
| 		 * it away in if and while statements */ | ||||
| 		if (strcmp(PyString_AS_STRING(e->v.Name.id), | ||||
| 		           "__debug__") == 0) | ||||
| 			   return ! Py_OptimizeFlag; | ||||
| 		/* fall through */ | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ | |||
| 
 | ||||
| #define IMPORT_STAR_WARNING "import * only allowed at module level" | ||||
| 
 | ||||
| #define RETURN_VAL_IN_GENERATOR \ | ||||
|     "'return' with argument inside generator" | ||||
| 
 | ||||
| /* XXX(nnorwitz): change name since static? */ | ||||
| static PySTEntryObject * | ||||
|  | @ -66,6 +68,7 @@ PySTEntry_New(struct symtable *st, identifier name, _Py_block_ty block, | |||
| 		ste->ste_nested = 1; | ||||
| 	ste->ste_child_free = 0; | ||||
| 	ste->ste_generator = 0; | ||||
| 	ste->ste_returns_value = 0; | ||||
| 
 | ||||
| 	if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) | ||||
| 	    goto fail; | ||||
|  | @ -944,8 +947,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) | |||
| 		break; | ||||
| 	} | ||||
|         case Return_kind: | ||||
| 		if (s->v.Return.value) | ||||
| 		if (s->v.Return.value) { | ||||
| 			VISIT(st, expr, s->v.Return.value); | ||||
| 			st->st_cur->ste_returns_value = 1; | ||||
| 			if (st->st_cur->ste_generator) { | ||||
| 				PyErr_SetString(PyExc_SyntaxError, | ||||
| 					RETURN_VAL_IN_GENERATOR); | ||||
| 			        PyErr_SyntaxLocation(st->st_filename, | ||||
| 				             s->lineno); | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
|         case Delete_kind: | ||||
| 		VISIT_SEQ(st, expr, s->v.Delete.targets); | ||||
|  | @ -1136,6 +1148,13 @@ symtable_visit_expr(struct symtable *st, expr_ty e) | |||
| 		if (e->v.Yield.value) | ||||
| 			VISIT(st, expr, e->v.Yield.value); | ||||
|                 st->st_cur->ste_generator = 1; | ||||
| 		if (st->st_cur->ste_returns_value) { | ||||
| 			PyErr_SetString(PyExc_SyntaxError, | ||||
| 				RETURN_VAL_IN_GENERATOR); | ||||
| 		        PyErr_SyntaxLocation(st->st_filename, | ||||
| 			             e->lineno); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		break; | ||||
|         case Compare_kind: | ||||
| 		VISIT(st, expr, e->v.Compare.left); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Georg Brandl
						Georg Brandl