Commit 0697212a authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter

Fix error handling in condition of while, do, and for statements

2008-11-30  Jürg Billeter  <j@bitron.ch>

	* vala/valaaddressofexpression.vala:
	* vala/valaarraycreationexpression.vala:
	* vala/valaassignment.vala:
	* vala/valabaseaccess.vala:
	* vala/valabinaryexpression.vala:
	* vala/valablock.vala:
	* vala/valacastexpression.vala:
	* vala/valaconditionalexpression.vala:
	* vala/valadostatement.vala:
	* vala/valaelementaccess.vala:
	* vala/valaexpression.vala:
	* vala/valaforstatement.vala:
	* vala/valainitializerlist.vala:
	* vala/valalambdaexpression.vala:
	* vala/valaliteral.vala:
	* vala/valamemberaccess.vala:
	* vala/valamethodcall.vala:
	* vala/valaobjectcreationexpression.vala:
	* vala/valaparenthesizedexpression.vala:
	* vala/valapointerindirection.vala:
	* vala/valapostfixexpression.vala:
	* vala/valareferencetransferexpression.vala:
	* vala/valasemanticanalyzer.vala:
	* vala/valasizeofexpression.vala:
	* vala/valaswitchsection.vala:
	* vala/valatuple.vala:
	* vala/valatypecheck.vala:
	* vala/valatypeofexpression.vala:
	* vala/valaunaryexpression.vala:
	* vala/valawhilestatement.vala:
	* gobject/valaccodebasemodule.vala:

	Fix error handling in condition of while, do, and for statements

svn path=/trunk/; revision=2096
parent 457053b1
2008-11-30 Jürg Billeter <j@bitron.ch>
* vala/valaaddressofexpression.vala:
* vala/valaarraycreationexpression.vala:
* vala/valaassignment.vala:
* vala/valabaseaccess.vala:
* vala/valabinaryexpression.vala:
* vala/valablock.vala:
* vala/valacastexpression.vala:
* vala/valaconditionalexpression.vala:
* vala/valadostatement.vala:
* vala/valaelementaccess.vala:
* vala/valaexpression.vala:
* vala/valaforstatement.vala:
* vala/valainitializerlist.vala:
* vala/valalambdaexpression.vala:
* vala/valaliteral.vala:
* vala/valamemberaccess.vala:
* vala/valamethodcall.vala:
* vala/valaobjectcreationexpression.vala:
* vala/valaparenthesizedexpression.vala:
* vala/valapointerindirection.vala:
* vala/valapostfixexpression.vala:
* vala/valareferencetransferexpression.vala:
* vala/valasemanticanalyzer.vala:
* vala/valasizeofexpression.vala:
* vala/valaswitchsection.vala:
* vala/valatuple.vala:
* vala/valatypecheck.vala:
* vala/valatypeofexpression.vala:
* vala/valaunaryexpression.vala:
* vala/valawhilestatement.vala:
* gobject/valaccodebasemodule.vala:
Fix error handling in condition of while, do, and for statements
2008-11-30 Jürg Billeter <j@bitron.ch>
* vala/valaexpressionstatement.vala:
......
......@@ -1207,6 +1207,7 @@ public class Vala.CCodeBaseModule : CCodeModule {
}
public override void visit_block (Block b) {
var old_symbol = current_symbol;
current_symbol = b;
b.accept_children (codegen);
......@@ -1258,7 +1259,7 @@ public class Vala.CCodeBaseModule : CCodeModule {
b.ccodenode = cblock;
current_symbol = current_symbol.parent_symbol;
current_symbol = old_symbol;
}
public override void visit_empty_statement (EmptyStatement stmt) {
......
......@@ -97,8 +97,4 @@ public class Vala.AddressofExpression : Expression {
return !error;
}
public override bool in_single_basic_block () {
return inner.in_single_basic_block ();
}
}
......@@ -220,13 +220,4 @@ public class Vala.ArrayCreationExpression : Expression {
return !error;
}
public override bool in_single_basic_block () {
foreach (Expression size in sizes) {
if (!size.in_single_basic_block ()) {
return false;
}
}
return true;
}
}
......@@ -400,10 +400,6 @@ public class Vala.Assignment : Expression {
}
right.get_used_variables (collection);
}
public override bool in_single_basic_block () {
return left.in_single_basic_block () && right.in_single_basic_block ();
}
}
public enum Vala.AssignmentOperator {
......
......@@ -88,8 +88,4 @@ public class Vala.BaseAccess : Expression {
return !error;
}
public override bool in_single_basic_block () {
return true;
}
}
......@@ -148,6 +148,9 @@ public class Vala.BinaryExpression : Expression {
checked = true;
if (operator == BinaryOperator.AND || operator == BinaryOperator.OR) {
var old_insert_block = analyzer.insert_block;
analyzer.insert_block = prepare_condition_split (analyzer);
// convert conditional expression into if statement
// required for flow analysis and exception handling
......@@ -172,12 +175,13 @@ public class Vala.BinaryExpression : Expression {
var if_stmt = new IfStatement (left, true_block, false_block, source_reference);
insert_statement ((Block) analyzer.current_symbol, decl);
insert_statement ((Block) analyzer.current_symbol, if_stmt);
insert_statement (analyzer.insert_block, decl);
insert_statement (analyzer.insert_block, if_stmt);
if (!if_stmt.check (analyzer)) {
return false;
}
analyzer.insert_block = old_insert_block;
var ma = new MemberAccess.simple (local.name, source_reference);
ma.target_type = target_type;
......@@ -350,14 +354,6 @@ public class Vala.BinaryExpression : Expression {
left.get_used_variables (collection);
right.get_used_variables (collection);
}
public override bool in_single_basic_block () {
if (operator == BinaryOperator.AND
|| operator == BinaryOperator.OR) {
return false;
}
return left.in_single_basic_block () && right.in_single_basic_block ();
}
}
public enum Vala.BinaryOperator {
......
......@@ -120,7 +120,9 @@ public class Vala.Block : Symbol, Statement {
owner = analyzer.current_symbol.scope;
var old_symbol = analyzer.current_symbol;
var old_insert_block = analyzer.insert_block;
analyzer.current_symbol = this;
analyzer.insert_block = this;
for (int i = 0; i < statement_list.size; i++) {
statement_list[i].check (analyzer);
......@@ -135,6 +137,7 @@ public class Vala.Block : Symbol, Statement {
}
analyzer.current_symbol = old_symbol;
analyzer.insert_block = old_insert_block;
return !error;
}
......
......@@ -131,8 +131,4 @@ public class Vala.CastExpression : Expression {
public override void get_used_variables (Collection<LocalVariable> collection) {
inner.get_used_variables (collection);
}
public override bool in_single_basic_block () {
return inner.in_single_basic_block ();
}
}
......@@ -105,6 +105,9 @@ public class Vala.ConditionalExpression : Expression {
checked = true;
var old_insert_block = analyzer.insert_block;
analyzer.insert_block = prepare_condition_split (analyzer);
// convert ternary expression into if statement
// required for flow analysis and exception handling
......@@ -128,12 +131,13 @@ public class Vala.ConditionalExpression : Expression {
var if_stmt = new IfStatement (condition, true_block, false_block, source_reference);
insert_statement ((Block) analyzer.current_symbol, decl);
insert_statement ((Block) analyzer.current_symbol, if_stmt);
insert_statement (analyzer.insert_block, decl);
insert_statement (analyzer.insert_block, if_stmt);
if (!if_stmt.check (analyzer)) {
return false;
}
analyzer.insert_block = old_insert_block;
true_expression = true_local.initializer;
false_expression = false_local.initializer;
......@@ -176,8 +180,4 @@ public class Vala.ConditionalExpression : Expression {
return true;
}
public override bool in_single_basic_block () {
return false;
}
}
......@@ -54,7 +54,7 @@ public class Vala.DoStatement : CodeNode, Statement {
private Expression _condition;
private Block _body;
/**
* Creates a new do statement.
*
......@@ -94,45 +94,6 @@ public class Vala.DoStatement : CodeNode, Statement {
checked = true;
if (!condition.in_single_basic_block ()) {
/* move condition into the loop body to allow split
* in multiple statements
*
* first = false;
* do {
* if (first) {
* if (!condition) {
* break;
* }
* }
* first = true;
* ...
* } while (true);
*/
var first_local = new LocalVariable (new ValueType (analyzer.bool_type.data_type), get_temp_name (), new BooleanLiteral (false, source_reference), source_reference);
var first_decl = new DeclarationStatement (first_local, source_reference);
first_decl.check (analyzer);
var block = (Block) analyzer.current_symbol;
block.insert_before (this, first_decl);
var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
var true_block = new Block (condition.source_reference);
true_block.add_statement (new BreakStatement (condition.source_reference));
var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
var condition_block = new Block (condition.source_reference);
condition_block.add_statement (if_stmt);
var first_if = new IfStatement (new MemberAccess.simple (first_local.name, source_reference), condition_block, null, source_reference);
body.insert_statement (0, first_if);
body.insert_statement (1, new ExpressionStatement (new Assignment (new MemberAccess.simple (first_local.name, source_reference), new BooleanLiteral (true, source_reference), AssignmentOperator.SIMPLE, source_reference), source_reference));
condition = new BooleanLiteral (true, source_reference);
}
body.check (analyzer);
if (!condition.check (analyzer)) {
/* if there was an error in the condition, skip this check */
error = true;
......@@ -145,9 +106,51 @@ public class Vala.DoStatement : CodeNode, Statement {
return false;
}
body.check (analyzer);
add_error_types (condition.get_error_types ());
add_error_types (body.get_error_types ());
return !error;
}
public Block prepare_condition_split (SemanticAnalyzer analyzer) {
/* move condition into the loop body to allow split
* in multiple statements
*
* first = false;
* do {
* if (first) {
* if (!condition) {
* break;
* }
* }
* first = true;
* ...
* } while (true);
*/
var first_local = new LocalVariable (new ValueType (analyzer.bool_type.data_type), get_temp_name (), new BooleanLiteral (false, source_reference), source_reference);
var first_decl = new DeclarationStatement (first_local, source_reference);
first_decl.check (analyzer);
var block = (Block) analyzer.current_symbol;
block.insert_before (this, first_decl);
var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
var true_block = new Block (condition.source_reference);
true_block.add_statement (new BreakStatement (condition.source_reference));
var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
var condition_block = new Block (condition.source_reference);
condition_block.add_statement (if_stmt);
var first_if = new IfStatement (new MemberAccess.simple (first_local.name, source_reference), condition_block, null, source_reference);
body.insert_statement (0, first_if);
body.insert_statement (1, new ExpressionStatement (new Assignment (new MemberAccess.simple (first_local.name, source_reference), new BooleanLiteral (true, source_reference), AssignmentOperator.SIMPLE, source_reference), source_reference));
condition = new BooleanLiteral (true, source_reference);
condition.check (analyzer);
return condition_block;
}
}
......@@ -222,13 +222,4 @@ public class Vala.ElementAccess : Expression {
index.get_used_variables (collection);
}
}
public override bool in_single_basic_block () {
foreach (Expression index in indices) {
if (!index.in_single_basic_block ()) {
return false;
}
}
return container.in_single_basic_block ();
}
}
......@@ -102,13 +102,23 @@ public abstract class Vala.Expression : CodeNode {
}
}
public Block prepare_condition_split (SemanticAnalyzer analyzer) {
var while_stmt = parent_statement as WhileStatement;
var do_stmt = parent_statement as DoStatement;
var for_stmt = parent_statement as ForStatement;
if (while_stmt != null) {
return while_stmt.prepare_condition_split (analyzer);
} else if (do_stmt != null) {
return do_stmt.prepare_condition_split (analyzer);
} else if (for_stmt != null) {
return for_stmt.prepare_condition_split (analyzer);
}
return analyzer.insert_block;
}
public void insert_statement (Block block, Statement stmt) {
block.insert_before (parent_statement, stmt);
}
/**
* Returns whether this expression is guaranteed to be part of a
* single basic block in the control flow graph.
*/
public abstract bool in_single_basic_block ();
}
......@@ -164,20 +164,6 @@ public class Vala.ForStatement : CodeNode, Statement {
checked = true;
if (condition != null && !condition.in_single_basic_block ()) {
// move condition into the loop body to allow split
// in multiple statements
var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
var true_block = new Block (condition.source_reference);
true_block.add_statement (new BreakStatement (condition.source_reference));
var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
body.insert_statement (0, if_stmt);
condition = new BooleanLiteral (true, source_reference);
}
foreach (Expression init_expr in initializer) {
init_expr.check (analyzer);
}
......@@ -218,4 +204,20 @@ public class Vala.ForStatement : CodeNode, Statement {
return !error;
}
public Block prepare_condition_split (SemanticAnalyzer analyzer) {
// move condition into the loop body to allow split
// in multiple statements
var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
var true_block = new Block (condition.source_reference);
true_block.add_statement (new BreakStatement (condition.source_reference));
var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
body.insert_statement (0, if_stmt);
condition = new BooleanLiteral (true, source_reference);
condition.check (analyzer);
return body;
}
}
......@@ -170,13 +170,4 @@ public class Vala.InitializerList : Expression {
return !error;
}
public override bool in_single_basic_block () {
foreach (Expression initializer in initializers) {
if (!initializer.in_single_basic_block ()) {
return false;
}
}
return true;
}
}
......@@ -203,8 +203,4 @@ public class Vala.LambdaExpression : Expression {
return !error;
}
public override bool in_single_basic_block () {
return true;
}
}
......@@ -33,8 +33,4 @@ public abstract class Vala.Literal : Expression {
public override bool is_pure () {
return true;
}
public override bool in_single_basic_block () {
return true;
}
}
......@@ -551,8 +551,4 @@ public class Vala.MemberAccess : Expression {
collection.add (local);
}
}
public override bool in_single_basic_block () {
return inner == null || inner.in_single_basic_block ();
}
}
......@@ -412,13 +412,16 @@ public class Vala.MethodCall : Expression {
if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
// simple statements, no side effects after method call
} else {
var old_insert_block = analyzer.insert_block;
analyzer.insert_block = prepare_condition_split (analyzer);
// store parent_node as we need to replace the expression in the old parent node later on
var old_parent_node = parent_node;
var local = new LocalVariable (value_type, get_temp_name (), null, source_reference);
var decl = new DeclarationStatement (local, source_reference);
insert_statement ((Block) analyzer.current_symbol, decl);
insert_statement (analyzer.insert_block, decl);
var temp_access = new MemberAccess.simple (local.name, source_reference);
temp_access.target_type = target_type;
......@@ -428,6 +431,8 @@ public class Vala.MethodCall : Expression {
decl.check (analyzer);
temp_access.check (analyzer);
analyzer.insert_block = old_insert_block;
old_parent_node.replace_expression (this, temp_access);
}
}
......@@ -450,13 +455,4 @@ public class Vala.MethodCall : Expression {
arg.get_used_variables (collection);
}
}
public override bool in_single_basic_block () {
foreach (Expression arg in argument_list) {
if (!arg.in_single_basic_block ()) {
return false;
}
}
return call.in_single_basic_block ();
}
}
......@@ -372,13 +372,4 @@ public class Vala.ObjectCreationExpression : Expression {
arg.get_used_variables (collection);
}
}
public override bool in_single_basic_block () {
foreach (Expression arg in argument_list) {
if (!arg.in_single_basic_block ()) {
return false;
}
}
return true;
}
}
......@@ -112,8 +112,4 @@ public class Vala.ParenthesizedExpression : Expression {
public override void get_used_variables (Collection<LocalVariable> collection) {
inner.get_used_variables (collection);
}
public override bool in_single_basic_block () {
return inner.in_single_basic_block ();
}
}
......@@ -109,8 +109,4 @@ public class Vala.PointerIndirection : Expression {
public override void get_used_variables (Collection<LocalVariable> collection) {
inner.get_used_variables (collection);
}
public override bool in_single_basic_block () {
return inner.in_single_basic_block ();
}
}
......@@ -75,8 +75,4 @@ public class Vala.PostfixExpression : Expression {
return !error;
}
public override bool in_single_basic_block () {
return true;
}
}
......@@ -115,8 +115,4 @@ public class Vala.ReferenceTransferExpression : Expression {
public override void get_used_variables (Collection<LocalVariable> collection) {
inner.get_used_variables (collection);
}
public override bool in_single_basic_block () {
return inner.in_single_basic_block ();
}
}
......@@ -37,6 +37,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
public Class current_class;
public Struct current_struct;
public Block insert_block;
public DataType bool_type;
public DataType string_type;
public DataType uchar_type;
......
......@@ -82,8 +82,4 @@ public class Vala.SizeofExpression : Expression {
return !error;
}
public override bool in_single_basic_block () {
return true;
}
}
......@@ -93,7 +93,11 @@ public class Vala.SwitchSection : Block {
}
owner = analyzer.current_symbol.scope;
var old_symbol = analyzer.current_symbol;
var old_insert_block = analyzer.insert_block;
analyzer.current_symbol = this;
analyzer.insert_block = this;
foreach (Statement st in get_statements ()) {
st.check (analyzer);
......@@ -103,7 +107,8 @@ public class Vala.SwitchSection : Block {
local.active = false;
}
analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
analyzer.current_symbol = old_symbol;
analyzer.insert_block = old_insert_block;
return !error;
}
......
......@@ -43,14 +43,5 @@ public class Vala.Tuple : Expression {
public override bool is_pure () {
return false;
}
public override bool in_single_basic_block () {
foreach (Expression expr in expression_list) {
if (!expr.in_single_basic_block ()) {
return false;
}
}
return true;
}
}
......@@ -101,8 +101,4 @@ public class Vala.TypeCheck : Expression {
return !error;
}
public override bool in_single_basic_block () {
return expression.in_single_basic_block ();
}
}
......@@ -84,8 +84,4 @@ public class Vala.TypeofExpression : Expression {
return !error;
}
public override bool in_single_basic_block () {
return true;
}
}
......@@ -241,10 +241,6 @@ public class Vala.UnaryExpression : Expression {
inner.get_used_variables (collection);
}
}
public override bool in_single_basic_block () {
return inner.in_single_basic_block ();
}
}
public enum Vala.UnaryOperator {
......
......@@ -94,19 +94,6 @@ public class Vala.WhileStatement : CodeNode, Statement {
checked = true;
if (!condition.in_single_basic_block ()) {
// move condition into the loop body to allow split
// in multiple statements
var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
var true_block = new Block (condition.source_reference);
true_block.add_statement (new BreakStatement (condition.source_reference));
var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
body.insert_statement (0, if_stmt);
condition = new BooleanLiteral (true, source_reference);
}
condition.check (analyzer);
body.check (analyzer);
......@@ -128,4 +115,21 @@ public class Vala.WhileStatement : CodeNode, Statement {
return !error;
}
public Block prepare_condition_split (SemanticAnalyzer analyzer) {
// move condition into the loop body to allow split
// in multiple statements
var if_condition = new UnaryExpression (UnaryOperator.LOGICAL_NEGATION, condition, condition.source_reference);
var true_block = new Block (condition.source_reference);
true_block.add_statement (new BreakStatement (condition.source_reference));
var if_stmt = new IfStatement (if_condition, true_block, null, condition.source_reference);
body.insert_statement (0, if_stmt);
condition = new BooleanLiteral (true, source_reference);
condition.check (analyzer);
return body;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment