]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Fix variadic constructors
authorSiegfried-Angel Gevatter Pujals <siegfried.gevatter@collabora.co.uk>
Fri, 6 Jul 2012 14:44:39 +0000 (16:44 +0200)
committerJürg Billeter <j@bitron.ch>
Mon, 30 Jul 2012 15:42:12 +0000 (17:42 +0200)
Fixes bug 620675.

codegen/valaccodebasemodule.vala
codegen/valaccodemethodmodule.vala
tests/Makefile.am
tests/objects/bug620675.vala [new file with mode: 0644]
vala/valamethod.vala

index 59888f39456e931bf96a40f2e2e22183574dfb0a..4762f574df32e96326b898ab048d0858142660bb 100644 (file)
@@ -4364,14 +4364,21 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        } else if (st != null && get_ccode_name (st) == "va_list") {
                                creation_call.add_argument (instance);
                                if (get_ccode_name (m) == "va_start") {
-                                       Parameter last_param = null;
-                                       foreach (var param in current_method.get_parameters ()) {
-                                               if (param.ellipsis) {
-                                                       break;
+                                       if (in_creation_method) {
+                                               creation_call = new CCodeFunctionCall (new CCodeIdentifier ("va_copy"));
+                                               creation_call.add_argument (instance);
+                                               creation_call.add_argument (new CCodeIdentifier ("_vala_va_list"));
+                                       } else {
+                                               Parameter last_param = null;
+                                               // FIXME: this doesn't take into account exception handling parameters
+                                               foreach (var param in current_method.get_parameters ()) {
+                                                       if (param.ellipsis) {
+                                                               break;
+                                                       }
+                                                       last_param = param;
                                                }
-                                               last_param = param;
+                                               creation_call.add_argument (new CCodeIdentifier (get_variable_cname (last_param.name)));
                                        }
-                                       creation_call.add_argument (new CCodeIdentifier (get_variable_cname (last_param.name)));
                                }
                        }
 
index 5559898b2fb63931aff42b4408bd2a5a6754a6c6..a784ab30eb66ec411771f6242032181c9495d11c 100644 (file)
@@ -27,6 +27,9 @@ using GLib;
  * The link between a method and generated code.
  */
 public abstract class Vala.CCodeMethodModule : CCodeStructModule {
+
+       private bool ellipses_to_valist = false;
+
        public override bool method_has_wrapper (Method method) {
                return (method.get_attribute ("NoWrapper") == null);
        }
@@ -175,7 +178,10 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 
                // do not generate _new functions for creation methods of abstract classes
                if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
+                       bool etv_tmp = ellipses_to_valist;
+                       ellipses_to_valist = false;
                        generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
+                       ellipses_to_valist = etv_tmp;
 
                        decl_space.add_function_declaration (function);
                }
@@ -189,9 +195,35 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                        }
 
                        cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+                       bool etv_tmp = ellipses_to_valist;
+                       ellipses_to_valist = false;
                        generate_cparameters (m, decl_space, cparam_map, function);
+                       ellipses_to_valist = etv_tmp;
 
                        decl_space.add_function_declaration (function);
+
+                       if (m.is_variadic ()) {
+                               // _constructv function
+                               function = new CCodeFunction (get_constructv_name ((CreationMethod) m));
+                               function.modifiers |= CCodeModifiers.STATIC;
+
+                               cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+                               generate_cparameters (m, decl_space, cparam_map, function);
+
+                               decl_space.add_function_declaration (function);
+                       }
+               }
+       }
+
+       private string get_constructv_name (CreationMethod m) {
+               const string infix = "constructv";
+
+               var parent = m.parent_symbol as Class;
+
+               if (m.name == ".new") {
+                       return "%s%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix);
+               } else {
+                       return "%s%s_%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix, m.name);
                }
        }
 
@@ -249,7 +281,18 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                ccode.add_expression (register_call);
        }
 
+       /**
+        * This function generates the code the given method. If the method is
+        * a constructor, _construct is generated, unless it's variadic, in which
+        * case _constructv is generated (and _construct is generated together
+        * with _new in visit_creation_method).
+        */
        public override void visit_method (Method m) {
+               string real_name = get_ccode_real_name (m);
+               if (m is CreationMethod && m.is_variadic ()) {
+                       real_name = get_constructv_name ((CreationMethod) m);
+               }
+
                push_context (new EmitContext (m));
                push_line (m.source_reference);
 
@@ -303,7 +346,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                }
 
                if (profile) {
-                       string prefix = "_vala_prof_%s".printf (get_ccode_real_name (m));
+                       string prefix = "_vala_prof_%s".printf (real_name);
 
                        cfile.add_include ("stdio.h");
 
@@ -364,12 +407,16 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                }
 
                CCodeFunction function;
-               function = new CCodeFunction (get_ccode_real_name (m));
+               function = new CCodeFunction (real_name);
 
                if (m.is_inline) {
                        function.modifiers |= CCodeModifiers.INLINE;
                }
 
+               if (m is CreationMethod && m.is_variadic ()) {
+                       function.modifiers |= CCodeModifiers.STATIC;
+               }
+
                var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
 
                generate_cparameters (m, cfile, cparam_map, function);
@@ -387,7 +434,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                                }
                        } else {
                                if (m.body != null) {
-                                       function = new CCodeFunction (get_ccode_real_name (m) + "_co", "gboolean");
+                                       function = new CCodeFunction (real_name + "_co", "gboolean");
 
                                        // data struct to hold parameters, local variables, and the return value
                                        function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*"));
@@ -628,7 +675,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                }
 
                if (profile) {
-                       string prefix = "_vala_prof_%s".printf (get_ccode_real_name (m));
+                       string prefix = "_vala_prof_%s".printf (real_name);
 
                        var level = new CCodeIdentifier (prefix + "_level");
                        ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level)));
@@ -649,7 +696,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                }
 
                if (profile) {
-                       string prefix = "_vala_prof_%s".printf (get_ccode_real_name (m));
+                       string prefix = "_vala_prof_%s".printf (real_name);
 
                        var level = new CCodeIdentifier (prefix + "_level");
                        ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
@@ -843,6 +890,8 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                        }
 
                        cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
+               } else if (ellipses_to_valist) {
+                       cparam = new CCodeParameter ("_vala_va_list", "va_list");
                } else {
                        cparam = new CCodeParameter.with_ellipsis ();
                }
@@ -1105,9 +1154,9 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
        public override void visit_creation_method (CreationMethod m) {
                push_line (m.source_reference);
 
-               bool visible = !m.is_private_symbol ();
-
+               ellipses_to_valist = true;
                visit_method (m);
+               ellipses_to_valist = false;
 
                if (m.source_type == SourceFileType.FAST) {
                        return;
@@ -1115,29 +1164,69 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 
                // do not generate _new functions for creation methods of abstract classes
                if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
-                       var vfunc = new CCodeFunction (get_ccode_name (m));
+                       // _new function
+                       create_aux_constructor (m, get_ccode_name (m), false);
 
-                       var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
-                       var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+                       // _construct function (if visit_method generated _constructv)
+                       if (m.is_variadic ()) {
+                               create_aux_constructor (m, get_ccode_real_name (m), true);
+                       }
+               }
 
-                       push_function (vfunc);
+               pop_line ();
+       }
+
+       private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) {
+               var vfunc = new CCodeFunction (func_name);
+               if (m.is_private_symbol ()) {
+                       vfunc.modifiers |= CCodeModifiers.STATIC;
+               }
 
-                       var vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
+               var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+               var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+               push_function (vfunc);
+
+               string constructor = (m.is_variadic ()) ? get_constructv_name (m) : get_ccode_real_name (m);
+               var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor));
+
+               if (self_as_first_parameter) {
+                       cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
+                       vcall.add_argument (get_variable_cexpression ("object_type"));
+               } else {
                        vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
+               }
 
-                       generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
-                       ccode.add_return (vcall);
 
-                       if (!visible) {
-                               vfunc.modifiers |= CCodeModifiers.STATIC;
+               generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
+
+               if (m.is_variadic ()) {
+                       int last_pos = -1;
+                       int second_last_pos = -1;
+                       foreach (int pos in cparam_map.get_keys ()) {
+                               if (pos > last_pos) {
+                                       second_last_pos = last_pos;
+                                       last_pos = pos;
+                               } else if (pos > second_last_pos) {
+                                       second_last_pos = pos;
+                               }
                        }
 
-                       pop_function ();
+                       var va_start = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
+                       va_start.add_argument (new CCodeIdentifier ("_vala_va_list_obj"));
+                       va_start.add_argument (carg_map.get (second_last_pos));
 
-                       cfile.add_function (vfunc);
+                       ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj"));
+                       ccode.add_expression (va_start);
+
+                       vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj"));
                }
 
-               pop_line ();
+               ccode.add_return (vcall);
+
+               pop_function ();
+
+               cfile.add_function (vfunc);
        }
 }
 
index 9a64c1d5e6e80fe66871195e4a6cd2c1a76badc9..6de7a7bb3bb4ff1c139667082da6b85b3ba7e7ad 100644 (file)
@@ -111,6 +111,7 @@ TESTS = \
        objects/bug597161.vala \
        objects/bug613486.vala \
        objects/bug613840.vala \
+       objects/bug620675.vala \
        objects/bug620706.vala \
        objects/bug624594.vala \
        objects/bug626038.vala \
diff --git a/tests/objects/bug620675.vala b/tests/objects/bug620675.vala
new file mode 100644 (file)
index 0000000..3a86fef
--- /dev/null
@@ -0,0 +1,65 @@
+public class Foo {
+
+       public GLib.GenericArray<string> paramlist;
+       public bool used_test;
+
+       public Foo (string msg, ...) throws Error {
+               string arg = msg;
+               va_list args = va_list ();
+               paramlist = new GLib.GenericArray<string> ();
+               while (arg != null) {
+                       paramlist.add (arg);
+                       arg = args.arg ();
+               }
+               used_test = false;
+       }
+
+       public Foo.test (string msg) {
+               paramlist = new GLib.GenericArray<string> ();
+               paramlist.add (msg);
+               used_test = true;
+       }
+
+}
+
+public class Bar : Foo {
+
+       public Bar (string text) throws Error {
+               base (text, "bye");
+       }
+
+       public Bar.other (int num, ...) {
+               try {
+                       base ("hey");
+               } catch (Error e) {
+               }
+       }
+
+}
+
+void main () {
+       Foo foo;
+
+       foo = new Foo ("one", "two", "three");
+       assert (!foo.used_test);
+       assert (foo.paramlist.length == 3);
+       assert (foo.paramlist[0] == "one");
+       assert (foo.paramlist[1] == "two");
+       assert (foo.paramlist[2] == "three");
+
+       foo = new Foo.test ("meh");
+       assert (foo.used_test);
+       assert (foo.paramlist.length == 1);
+       assert (foo.paramlist[0] == "meh");
+
+       foo = new Bar ("hello");
+       assert (!foo.used_test);
+       assert (foo.paramlist.length == 2);
+       assert (foo.paramlist[0] == "hello");
+       assert (foo.paramlist[1] == "bye");
+
+       foo = new Bar.other (1, 2, 3);
+       assert (!foo.used_test);
+       assert (foo.paramlist.length == 1);
+       assert (foo.paramlist[0] == "hey");
+}
index 9f397c4cc36b99ba25acf6f324f5d208b6f61e0c..2a1bf81a2ac3864f2218dbf788359994cb9ab9d0 100644 (file)
@@ -231,6 +231,15 @@ public class Vala.Method : Subroutine {
                parameters.clear ();
        }
 
+       public bool is_variadic () {
+               foreach (Parameter param in parameters) {
+                       if (param.ellipsis) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
        public override void accept (CodeVisitor visitor) {
                visitor.visit_method (this);
        }