diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index d94ce2501..449f00f06 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -195,6 +195,7 @@ CPP_TEST_CASES += \ evil_diamond_prop \ exception_order \ extend \ + extend_constructor_destructor \ extend_default \ extend_placement \ extend_template \ diff --git a/Examples/test-suite/extend_constructor_destructor.i b/Examples/test-suite/extend_constructor_destructor.i new file mode 100644 index 000000000..dbb47245d --- /dev/null +++ b/Examples/test-suite/extend_constructor_destructor.i @@ -0,0 +1,105 @@ +%module extend_constructor_destructor + +%inline %{ +int global = 0; + +namespace Space { + typedef struct tagAStruct { + int ivar; + } AStruct; + + struct BStruct { + int ivar; + }; + + typedef struct tagCStruct { + int ivar; + } CStruct; + + // Unnamed struct + typedef struct { + int ivar; + } DStruct; +} + +typedef struct tagEStruct { + int ivar; +} EStruct; + +%} + +%extend Junk { +void thingy() {} +} +%inline %{ +struct Junk {}; +%} +namespace Space { + +%extend tagAStruct { + tagAStruct(int ivar0) { + Space::AStruct *s = new Space::AStruct(); + s->ivar = ivar0; + global = ivar0; + return s; + } + ~tagAStruct() { + global = -$self->ivar; + delete $self; + } +} + +%extend BStruct { + BStruct(int ivar0) { + Space::BStruct *s = new Space::BStruct(); + s->ivar = ivar0; + global = ivar0; + return s; + } + ~BStruct() { + global = -$self->ivar; + delete $self; + } +} + +%extend CStruct { + CStruct(int ivar0) { + Space::CStruct *s = new Space::CStruct(); + s->ivar = ivar0; + global = ivar0; + return s; + } + ~CStruct() { + global = -$self->ivar; + delete $self; + } +} + +%extend DStruct { + DStruct(int ivar0) { + Space::DStruct *s = new Space::DStruct(); + s->ivar = ivar0; + global = ivar0; + return s; + } + ~DStruct() { + global = -$self->ivar; + delete $self; + } +} + +} + +%extend EStruct { + EStruct(int ivar0) { + EStruct *s = new EStruct(); + s->ivar = ivar0; + global = ivar0; + return s; + } + ~EStruct() { + global = -$self->ivar; + delete $self; + } +} + diff --git a/Examples/test-suite/java/extend_constructor_destructor_runme.java b/Examples/test-suite/java/extend_constructor_destructor_runme.java new file mode 100644 index 000000000..270bc17e1 --- /dev/null +++ b/Examples/test-suite/java/extend_constructor_destructor_runme.java @@ -0,0 +1,40 @@ +import extend_constructor_destructor.*; + +public class extend_constructor_destructor_runme { + + static { + try { + System.loadLibrary("extend_constructor_destructor"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) { + AStruct a = new AStruct(10); + checkGlobal(10); + BStruct b = new BStruct(20); + checkGlobal(20); + CStruct c = new CStruct(30); + checkGlobal(30); + DStruct d = new DStruct(40); + checkGlobal(40); + + a.delete(); + checkGlobal(-10); + b.delete(); + checkGlobal(-20); + c.delete(); + checkGlobal(-30); + d.delete(); + checkGlobal(-40); + } + + public static void checkGlobal(int val) { + int global = extend_constructor_destructor.getGlobal(); + if (global != val) + throw new RuntimeException("global value incorrect. Expected: " + val + " got: " + global); + } +} + diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index 1b7ab6840..44a9d2edc 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -2288,9 +2288,7 @@ static void addDestructor(Node *n) { String *decl = NewString("f()."); String *symname = Swig_name_make(cn, cname, last, decl, 0); if (Strcmp(symname, "$ignore") != 0) { - if (!symname) { - symname = NewStringf("~%s", Getattr(n, "sym:name")); - } + String *possible_nonstandard_symname = NewStringf("~%s", Getattr(n, "sym:name")); Setattr(cn, "name", name); Setattr(cn, "sym:name", symname); @@ -2298,20 +2296,27 @@ static void addDestructor(Node *n) { Setattr(cn, "parentNode", n); Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *nonstandard_destructor = Equal(possible_nonstandard_symname, symname) ? 0 : Swig_symbol_clookup(possible_nonstandard_symname, 0); Node *on = Swig_symbol_add(symname, cn); Swig_symbol_setscope(oldscope); Swig_features_get(Swig_cparse_features(), 0, name, decl, cn); if (on == cn) { - Node *access = NewHash(); - set_nodeType(access, "access"); - Setattr(access, "kind", "public"); - appendChild(n, access); - appendChild(n, cn); - Setattr(n, "has_destructor", "1"); - Setattr(n, "allocate:destructor", "1"); - Delete(access); + // SWIG accepts a non-standard named destructor in %extend that uses a typedef for the destructor name + // For example: typedef struct X {} XX; %extend X { ~XX() {...} } + // Don't add another destructor if a nonstandard one has been declared + if (!nonstandard_destructor) { + Node *access = NewHash(); + set_nodeType(access, "access"); + Setattr(access, "kind", "public"); + appendChild(n, access); + appendChild(n, cn); + Setattr(n, "has_destructor", "1"); + Setattr(n, "allocate:destructor", "1"); + Delete(access); + } } + Delete(possible_nonstandard_symname); } Delete(cn); Delete(last); @@ -2604,10 +2609,21 @@ int Language::constructorDeclaration(Node *n) { } } } else { - if (name && (Cmp(Swig_scopename_last(name), Swig_scopename_last(ClassName))) && !(Getattr(n, "template"))) { - Swig_warning(WARN_LANG_RETURN_TYPE, input_file, line_number, "Function %s must have a return type. Ignored.\n", SwigType_namestr(name)); - Swig_restore(n); - return SWIG_NOWRAP; + if (name && (!Equal(Swig_scopename_last(name), Swig_scopename_last(ClassName))) && !(Getattr(n, "template"))) { + bool illegal_method = true; + if (Extend) { + // SWIG extension - allow typedef names as constructor name in %extend - an unnamed struct declared with a typedef can thus be given a 'constructor'. + SwigType *name_resolved = SwigType_typedef_resolve_all(name); + SwigType *classname_resolved = SwigType_typedef_resolve_all(ClassName); + illegal_method = !Equal(name_resolved, classname_resolved); + Delete(name_resolved); + Delete(classname_resolved); + } + if (illegal_method) { + Swig_warning(WARN_LANG_RETURN_TYPE, input_file, line_number, "Function %s must have a return type. Ignored.\n", SwigType_namestr(name)); + Swig_restore(n); + return SWIG_NOWRAP; + } } constructorHandler(n); } @@ -2712,7 +2728,7 @@ int Language::destructorDeclaration(Node *n) { return SWIG_NOWRAP; if (Extend) { - /* extend destructor can be safetly ignored if there is already one */ + /* extend destructor can be safely ignored if there is already one */ if (Getattr(CurrentClass, "has_destructor")) { return SWIG_NOWRAP; }