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_generator : 1;   /* true if namespace is a generator */ | ||||||
| 	unsigned ste_varargs : 1;     /* true if block has varargs */ | 	unsigned ste_varargs : 1;     /* true if block has varargs */ | ||||||
| 	unsigned ste_varkeywords : 1; /* true if block has varkeywords */ | 	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_lineno;          /* first line of block */ | ||||||
| 	int ste_opt_lineno;      /* lineno of last exec or import * */ | 	int ste_opt_lineno;      /* lineno of last exec or import * */ | ||||||
| 	int ste_tmpname;         /* counter for listcomp temp vars */ | 	int ste_tmpname;         /* counter for listcomp temp vars */ | ||||||
|  |  | ||||||
|  | @ -733,7 +733,7 @@ | ||||||
| ...     yield 1 | ...     yield 1 | ||||||
| Traceback (most recent call last): | 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(): | >>> def f(): | ||||||
| ...     yield 1 | ...     yield 1 | ||||||
|  | @ -876,9 +876,9 @@ | ||||||
| ...         if 0: | ...         if 0: | ||||||
| ...             return 3        # but *this* sucks (line 8) | ...             return 3        # but *this* sucks (line 8) | ||||||
| ...     if 0: | ...     if 0: | ||||||
| ...         yield 2             # because it's a generator | ...         yield 2             # because it's a generator (line 10) | ||||||
| Traceback (most recent call last): | 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): | 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 | 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 | - Builtin exceptions are now full-blown new-style classes instead of | ||||||
|   instances pretending to be classes, which speeds up exception handling |   instances pretending to be classes, which speeds up exception handling | ||||||
|   by about 80% in comparison to 2.5a2. |   by about 80% in comparison to 2.5a2. | ||||||
|  |  | ||||||
|  | @ -2148,7 +2148,7 @@ static int | ||||||
| compiler_if(struct compiler *c, stmt_ty s) | compiler_if(struct compiler *c, stmt_ty s) | ||||||
| { | { | ||||||
| 	basicblock *end, *next; | 	basicblock *end, *next; | ||||||
| 
 | 	int constant; | ||||||
| 	assert(s->kind == If_kind); | 	assert(s->kind == If_kind); | ||||||
| 	end = compiler_new_block(c); | 	end = compiler_new_block(c); | ||||||
| 	if (end == NULL) | 	if (end == NULL) | ||||||
|  | @ -2156,15 +2156,27 @@ compiler_if(struct compiler *c, stmt_ty s) | ||||||
| 	next = compiler_new_block(c); | 	next = compiler_new_block(c); | ||||||
| 	if (next == NULL) | 	if (next == NULL) | ||||||
| 	    return 0; | 	    return 0; | ||||||
| 	VISIT(c, expr, s->v.If.test); | 	 | ||||||
| 	ADDOP_JREL(c, JUMP_IF_FALSE, next); | 	constant = expr_constant(s->v.If.test); | ||||||
| 	ADDOP(c, POP_TOP); | 	/* constant = 0: "if 0"
 | ||||||
| 	VISIT_SEQ(c, stmt, s->v.If.body); | 	 * constant = 1: "if 1", "if 2", ... | ||||||
| 	ADDOP_JREL(c, JUMP_FORWARD, end); | 	 * constant = -1: rest */ | ||||||
| 	compiler_use_next_block(c, next); | 	if (constant == 0) { | ||||||
| 	ADDOP(c, POP_TOP); | 		if (s->v.If.orelse) | ||||||
| 	if (s->v.If.orelse) | 			VISIT_SEQ(c, stmt, 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); | ||||||
|  | 		VISIT_SEQ(c, stmt, s->v.If.body); | ||||||
|  | 		ADDOP_JREL(c, JUMP_FORWARD, end); | ||||||
|  | 		compiler_use_next_block(c, next); | ||||||
|  | 		ADDOP(c, POP_TOP); | ||||||
|  | 		if (s->v.If.orelse) | ||||||
|  | 	    		VISIT_SEQ(c, stmt, s->v.If.orelse); | ||||||
|  | 	} | ||||||
| 	compiler_use_next_block(c, end); | 	compiler_use_next_block(c, end); | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
|  | @ -2639,10 +2651,6 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) | ||||||
| 		if (c->u->u_ste->ste_type != FunctionBlock) | 		if (c->u->u_ste->ste_type != FunctionBlock) | ||||||
| 			return compiler_error(c, "'return' outside function"); | 			return compiler_error(c, "'return' outside function"); | ||||||
| 		if (s->v.Return.value) { | 		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); | 			VISIT(c, expr, s->v.Return.value); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
|  | @ -3356,6 +3364,13 @@ expr_constant(expr_ty e) | ||||||
| 		return PyObject_IsTrue(e->v.Num.n); | 		return PyObject_IsTrue(e->v.Num.n); | ||||||
| 	case Str_kind: | 	case Str_kind: | ||||||
| 		return PyObject_IsTrue(e->v.Str.s); | 		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: | 	default: | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -13,6 +13,8 @@ | ||||||
| 
 | 
 | ||||||
| #define IMPORT_STAR_WARNING "import * only allowed at module level" | #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? */ | /* XXX(nnorwitz): change name since static? */ | ||||||
| static PySTEntryObject * | static PySTEntryObject * | ||||||
|  | @ -66,6 +68,7 @@ PySTEntry_New(struct symtable *st, identifier name, _Py_block_ty block, | ||||||
| 		ste->ste_nested = 1; | 		ste->ste_nested = 1; | ||||||
| 	ste->ste_child_free = 0; | 	ste->ste_child_free = 0; | ||||||
| 	ste->ste_generator = 0; | 	ste->ste_generator = 0; | ||||||
|  | 	ste->ste_returns_value = 0; | ||||||
| 
 | 
 | ||||||
| 	if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) | 	if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) | ||||||
| 	    goto fail; | 	    goto fail; | ||||||
|  | @ -944,8 +947,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
|         case Return_kind: |         case Return_kind: | ||||||
| 		if (s->v.Return.value) | 		if (s->v.Return.value) { | ||||||
| 			VISIT(st, expr, 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; | 		break; | ||||||
|         case Delete_kind: |         case Delete_kind: | ||||||
| 		VISIT_SEQ(st, expr, s->v.Delete.targets); | 		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) | 		if (e->v.Yield.value) | ||||||
| 			VISIT(st, expr, e->v.Yield.value); | 			VISIT(st, expr, e->v.Yield.value); | ||||||
|                 st->st_cur->ste_generator = 1; |                 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; | 		break; | ||||||
|         case Compare_kind: |         case Compare_kind: | ||||||
| 		VISIT(st, expr, e->v.Compare.left); | 		VISIT(st, expr, e->v.Compare.left); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Georg Brandl
						Georg Brandl