From: Luca Bruno Date: Wed, 20 Mar 2013 23:32:19 +0000 (+0000) Subject: codegen: Destroy value of "as" cast in case the result is null X-Git-Tag: 0.20.0~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fd55b251c171d89bb5754b601f4a99981d0b3916;p=thirdparty%2Fvala.git codegen: Destroy value of "as" cast in case the result is null Fixes bug 695671. --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 93d04eeec..a8d9e8cca 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -3200,8 +3200,6 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { return destroy_value (get_field_cvalue (field, instance)); } - // logic in this method is temporarily duplicated in destroy_variable - // apply changes to both methods public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) { var type = value.value_type; if (value.actual_value_type != null) { @@ -3757,6 +3755,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { (st == null || get_ccode_name (st) != "va_list")) { // GArray and va_list don't use pointer-based generics set_cvalue (expr, convert_from_generic_pointer (get_cvalue (expr), expr.value_type)); + ((GLibValue) expr.target_value).lvalue = false; } } @@ -3775,6 +3774,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { if (expr.formal_target_type.type_parameter.parent_symbol != garray_type) { // GArray doesn't use pointer-based generics set_cvalue (expr, convert_to_generic_pointer (get_cvalue (expr), expr.target_type)); + ((GLibValue) expr.target_value).lvalue = false; } } @@ -5015,12 +5015,25 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { if (iface != null || (cl != null && !cl.is_compact)) { // checked cast for strict subtypes of GTypeInstance if (expr.is_silent_cast) { - var cexpr = get_cvalue (expr.inner); + TargetValue to_cast = expr.inner.target_value; + CCodeExpression cexpr; + if (!get_lvalue (to_cast)) { + to_cast = store_temp_value (to_cast, expr); + } + cexpr = get_cvalue_ (to_cast); var ccheck = create_type_check (cexpr, expr.type_reference); var ccast = new CCodeCastExpression (cexpr, get_ccode_name (expr.type_reference)); var cnull = new CCodeConstant ("NULL"); - - set_cvalue (expr, new CCodeConditionalExpression (ccheck, ccast, cnull)); + var cast_value = new GLibValue (expr.value_type, new CCodeConditionalExpression (ccheck, ccast, cnull)); + if (requires_destroy (expr.inner.value_type)) { + var casted = store_temp_value (cast_value, expr); + ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_cvalue_ (casted), new CCodeConstant ("NULL"))); + ccode.add_expression (destroy_value (to_cast)); + ccode.close (); + expr.target_value = ((GLibValue) casted).copy (); + } else { + expr.target_value = cast_value; + } } else { set_cvalue (expr, generate_instance_cast (get_cvalue (expr.inner), expr.type_reference.data_type)); } @@ -5632,7 +5645,10 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, result.cvalue); } else { + // TODO: rewrite get_implicit_cast_expression to return a GLibValue + var old_cexpr = result.cvalue; result.cvalue = get_implicit_cast_expression (result.cvalue, type, target_type, node); + result.lvalue = result.lvalue && result.cvalue == old_cexpr; } if (requires_temp_value && !(target_type is ArrayType && ((ArrayType) target_type).inline_allocated)) { diff --git a/tests/Makefile.am b/tests/Makefile.am index eedf8ced0..c11565c7c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -131,6 +131,7 @@ TESTS = \ objects/bug664529.vala \ objects/bug667668.vala \ objects/bug683646.vala \ + objects/bug695671.vala \ errors/errors.vala \ errors/bug567181.vala \ errors/bug579101.vala \ diff --git a/tests/objects/bug695671.vala b/tests/objects/bug695671.vala new file mode 100644 index 000000000..fb06be990 --- /dev/null +++ b/tests/objects/bug695671.vala @@ -0,0 +1,37 @@ +class Foo : Object { +} + +G ref_generic (G o) { + return o; +} + +Object ref (Object o) { + return o; +} + +void main () { + var o = new Object(); + var f = (ref (o)) as Foo; + assert (f == null); + assert (o.ref_count == 1); + + var g = (ref_generic (o)) as Foo; + assert (g == null); + assert (o.ref_count == 1); + + var r = ref_generic (o) as Object; + assert (r == o); + assert (o.ref_count == 2); + + var r2 = o as Object; + assert (r2 == o); + assert (o.ref_count == 3); + + unowned Object r3 = o as Object; + assert (r3 == o); + assert (o.ref_count == 3); + + unowned Object r4 = o as Foo; + assert (r4 == null); + assert (o.ref_count == 3); +}