Commit 94dbe36a authored by Siegfried-Angel Gevatter Pujals's avatar Siegfried-Angel Gevatter Pujals Committed by Jürg Billeter

codegen: Fix variadic constructors

Fixes bug 620675.
parent 84f26835
......@@ -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)));
}
}
......
......@@ -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);
}
}
......
......@@ -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 \
......
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");
}
......@@ -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);
}
......
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