diff --git a/CHANGES.current b/CHANGES.current index 4b3a2679c..663f2c451 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -4,6 +4,7 @@ See the RELEASENOTES file for a summary of changes in each release. Version 2.0.8 (in progress) =========================== + 2012-06-27: wsfulton Fix display of pointers in various places on 64 bit systems - only 32 bits were being shown. @@ -15,6 +16,45 @@ Version 2.0.8 (in progress) 2012-07-20: kwwette [Octave] segfault-on-exit prevention hack now preserves exit status, and uses C99 _Exit(). +2012-06-30: wsfulton + Fix namespace problems for symbols declared with a forward class declarations, such as: + + namespace Space1 { + namespace Space2 { + struct XXX; + struct YYY; + } + + struct Space2::YYY {}; + struct Space1::Space2::XXX {}; + + void testXXX2(Space2::XXX xx) {} + void testYYY2(Space2::YYY yy) {} + } + + where xx and yy were not recognised as the proxy classes XXX and YYY. + +2012-06-30: wsfulton + Fix using declarations combined with using directives with forward class declarations so that + types are correctly found in scope. + + namespace Outer2 { + namespace Space2 { + class Thing2; + } + } + using namespace Outer2; + using Space2::Thing2; + class Thing2 {}; + // None of the methods below correctly used the Thing2 proxy class + void useit2(Thing2 t) {} + void useit2a(Outer2::Space2::Thing2 t) {} + void useit2b(::Outer2::Space2::Thing2 t) {} + void useit2c(Space2::Thing2 t) {} + namespace Outer2 { + void useit2d(Space2::Thing2 t) {} + } + 2012-06-25: wsfulton Fix using declarations combined with using directives so that types are correctly found in scope. Example: @@ -28,6 +68,8 @@ Version 2.0.8 (in progress) using Space2::Thing2; // using declaration void useit2(Thing2 t) {} + Similarly for templated classes. + 2012-05-29: wsfulton Fix #3529601 - seg fault when a protected method has the "director" feature but the parent class does not. Also fix similar problems with diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index fd7ecb1f3..db13a9fbe 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -257,6 +257,7 @@ CPP_TEST_CASES += \ namespace_class \ namespace_enum \ namespace_extend \ + namespace_forward_declaration \ namespace_nested \ namespace_spaces \ namespace_template \ @@ -443,6 +444,7 @@ CPP_TEST_CASES += \ using2 \ using_composition \ using_directive_and_declaration \ + using_directive_and_declaration_forward \ using_extend \ using_inherit \ using_namespace \ diff --git a/Examples/test-suite/java/namespace_forward_declaration_runme.java b/Examples/test-suite/java/namespace_forward_declaration_runme.java new file mode 100644 index 000000000..c603ebacf --- /dev/null +++ b/Examples/test-suite/java/namespace_forward_declaration_runme.java @@ -0,0 +1,26 @@ + +import namespace_forward_declaration.*; + +public class namespace_forward_declaration_runme { + + static { + try { + System.loadLibrary("namespace_forward_declaration"); + } 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[]) { + XXX xxx = new XXX(); + namespace_forward_declaration.testXXX1(xxx); + namespace_forward_declaration.testXXX2(xxx); + namespace_forward_declaration.testXXX3(xxx); + YYY yyy = new YYY(); + namespace_forward_declaration.testYYY1(yyy); + namespace_forward_declaration.testYYY2(yyy); + namespace_forward_declaration.testYYY3(yyy); + } +} + diff --git a/Examples/test-suite/java/using_directive_and_declaration_forward_runme.java b/Examples/test-suite/java/using_directive_and_declaration_forward_runme.java new file mode 100644 index 000000000..916aeb703 --- /dev/null +++ b/Examples/test-suite/java/using_directive_and_declaration_forward_runme.java @@ -0,0 +1,53 @@ + +import using_directive_and_declaration_forward.*; + +public class using_directive_and_declaration_forward_runme { + + static { + try { + System.loadLibrary("using_directive_and_declaration_forward"); + } 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[]) + { + using_directive_and_declaration_forward.useit1(new Thing1()); + using_directive_and_declaration_forward.useit1a(new Thing1()); + using_directive_and_declaration_forward.useit1b(new Thing1()); + using_directive_and_declaration_forward.useit1c(new Thing1()); + + using_directive_and_declaration_forward.useit2(new Thing2()); + using_directive_and_declaration_forward.useit2a(new Thing2()); + using_directive_and_declaration_forward.useit2b(new Thing2()); + using_directive_and_declaration_forward.useit2c(new Thing2()); + using_directive_and_declaration_forward.useit2d(new Thing2()); + + using_directive_and_declaration_forward.useit3(new Thing3()); + using_directive_and_declaration_forward.useit3a(new Thing3()); + using_directive_and_declaration_forward.useit3b(new Thing3()); + using_directive_and_declaration_forward.useit3c(new Thing3()); + using_directive_and_declaration_forward.useit3d(new Thing3()); + + using_directive_and_declaration_forward.useit4(new Thing4()); + using_directive_and_declaration_forward.useit4a(new Thing4()); + using_directive_and_declaration_forward.useit4b(new Thing4()); + using_directive_and_declaration_forward.useit4c(new Thing4()); + using_directive_and_declaration_forward.useit4d(new Thing4()); + + using_directive_and_declaration_forward.useit5(new Thing5()); + using_directive_and_declaration_forward.useit5a(new Thing5()); + using_directive_and_declaration_forward.useit5b(new Thing5()); + using_directive_and_declaration_forward.useit5c(new Thing5()); + using_directive_and_declaration_forward.useit5d(new Thing5()); + + + using_directive_and_declaration_forward.useit7(new Thing7()); + using_directive_and_declaration_forward.useit7a(new Thing7()); + using_directive_and_declaration_forward.useit7b(new Thing7()); + using_directive_and_declaration_forward.useit7c(new Thing7()); + using_directive_and_declaration_forward.useit7d(new Thing7()); + } +} diff --git a/Examples/test-suite/java/using_directive_and_declaration_runme.java b/Examples/test-suite/java/using_directive_and_declaration_runme.java index 2be189dd5..29e0fd2c9 100644 --- a/Examples/test-suite/java/using_directive_and_declaration_runme.java +++ b/Examples/test-suite/java/using_directive_and_declaration_runme.java @@ -24,5 +24,6 @@ public class using_directive_and_declaration_runme { Thing6 t6b = new Thing6(); t6b.b(); using_directive_and_declaration.useit6(t6a, t6b); + using_directive_and_declaration.useit7(new Thing7()); } } diff --git a/Examples/test-suite/namespace_forward_declaration.i b/Examples/test-suite/namespace_forward_declaration.i new file mode 100644 index 000000000..ad7c48d86 --- /dev/null +++ b/Examples/test-suite/namespace_forward_declaration.i @@ -0,0 +1,35 @@ +%module namespace_forward_declaration + +%inline %{ + namespace Space1 { + namespace Space2 { + struct XXX; + struct YYY; + } + + struct Space2::YYY { + int yyy(int h) { + return h; + } + }; + struct Space1::Space2::XXX { + int xxx(int h) { + return h; + } + }; + + void testXXX1(Space1::Space2::XXX xx) { + } + void testXXX2(Space2::XXX xx) { + } + void testXXX3(::Space1::Space2::XXX xx) { + } + void testYYY1(Space1::Space2::YYY yy) { + } + void testYYY2(Space2::YYY yy) { + } + void testYYY3(::Space1::Space2::YYY yy) { + } + } +%} + diff --git a/Examples/test-suite/using_directive_and_declaration.i b/Examples/test-suite/using_directive_and_declaration.i index 7196d39f1..27c7f199c 100644 --- a/Examples/test-suite/using_directive_and_declaration.i +++ b/Examples/test-suite/using_directive_and_declaration.i @@ -81,5 +81,26 @@ namespace Outer6 { } using namespace Outer6::Space6b; void useit6(Outer6::Space6a::Thing6 ta, Thing6 tb) {} + +namespace Outer7 { + namespace Space7 { + namespace Middle7 { + class Thing7; + } + } +} +using namespace Outer7::Space7; +class Middle7::Thing7 {}; +using Middle7::Thing7; +void useit7(Thing7 t) {} +void useit7a(Outer7::Space7::Middle7::Thing7 t) {} +void useit7b(::Outer7::Space7::Middle7::Thing7 t) {} +void useit7c(Middle7::Thing7 t) {} +namespace Outer7 { + namespace Space7 { + void useit7d(Middle7::Thing7 t) {} + } +} + %} diff --git a/Examples/test-suite/using_directive_and_declaration_forward.i b/Examples/test-suite/using_directive_and_declaration_forward.i new file mode 100644 index 000000000..238b3b77f --- /dev/null +++ b/Examples/test-suite/using_directive_and_declaration_forward.i @@ -0,0 +1,124 @@ +%module using_directive_and_declaration_forward +// Test using directives combined with using declarations and forward declarations + +%inline %{ +namespace Outer1 { + namespace Space1 { + class Thing1; + } +} +using namespace Outer1::Space1; +using Outer1::Space1::Thing1; +class Thing1 {}; +void useit1(Thing1 t) {} +void useit1a(Outer1::Space1::Thing1 t) {} +void useit1b(::Outer1::Space1::Thing1 t) {} +namespace Outer1 { + void useit1c(Space1::Thing1 t) {} +} + + +namespace Outer2 { + namespace Space2 { + class Thing2; + } +} +using namespace Outer2; +using Space2::Thing2; +class Thing2 {}; +void useit2(Thing2 t) {} +void useit2a(Outer2::Space2::Thing2 t) {} +void useit2b(::Outer2::Space2::Thing2 t) {} +void useit2c(Space2::Thing2 t) {} +namespace Outer2 { + void useit2d(Space2::Thing2 t) {} +} + + +namespace Outer3 { + namespace Space3 { + namespace Middle3 { + class Thing3; + } + } +} +using namespace Outer3; +using namespace Space3; +using Middle3::Thing3; +class Thing3 {}; +void useit3(Thing3 t) {} +void useit3a(Outer3::Space3::Middle3::Thing3 t) {} +void useit3b(::Outer3::Space3::Middle3::Thing3 t) {} +void useit3c(Middle3::Thing3 t) {} +namespace Outer3 { + namespace Space3 { + void useit3d(Middle3::Thing3 t) {} + } +} + + +namespace Outer4 { + namespace Space4 { + namespace Middle4 { + class Thing4; + } + } +} +using namespace Outer4::Space4; +using Middle4::Thing4; +class Thing4 {}; +void useit4(Thing4 t) {} +void useit4a(Outer4::Space4::Middle4::Thing4 t) {} +void useit4b(::Outer4::Space4::Middle4::Thing4 t) {} +void useit4c(Middle4::Thing4 t) {} +namespace Outer4 { + namespace Space4 { + void useit4d(Middle4::Thing4 t) {} + } +} + + +namespace Outer5 { + namespace Space5 { + namespace Middle5 { + namespace More5 { + class Thing5; + } + } + } +} +using namespace ::Outer5::Space5; +using namespace Middle5; +using More5::Thing5; +class Thing5 {}; +void useit5(Thing5 t) {} +void useit5a(Outer5::Space5::Middle5::More5::Thing5 t) {} +void useit5b(::Outer5::Space5::Middle5::More5::Thing5 t) {} +void useit5c(Middle5::More5::Thing5 t) {} +namespace Outer5 { + namespace Space5 { + void useit5d(Middle5::More5::Thing5 t) {} + } +} + +namespace Outer7 { + namespace Space7 { + namespace Middle7 { + class Thing7; + } + } +} +using namespace Outer7::Space7; +class Middle7::Thing7 {}; +using Middle7::Thing7; +void useit7(Thing7 t) {} +void useit7a(Outer7::Space7::Middle7::Thing7 t) {} +void useit7b(::Outer7::Space7::Middle7::Thing7 t) {} +void useit7c(Middle7::Thing7 t) {} +namespace Outer7 { + namespace Space7 { + void useit7d(Middle7::Thing7 t) {} + } +} + +%} diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 27344598a..b400efa3a 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -205,7 +205,7 @@ static String *yyrename = 0; /* Forward renaming operator */ -static String *resolve_node_scope(String *cname); +static String *resolve_create_node_scope(String *cname); Hash *Swig_cparse_features(void) { @@ -867,26 +867,86 @@ static Node *nscope = 0; static Node *nscope_inner = 0; /* Remove the scope prefix from cname and return the base name without the prefix. - * The scopes specified in the prefix are found, or created in the current namespace. - * So ultimately the scope is changed to that required for the base name. + * The scopes required for the symbol name are resolved and/or created, if required. * For example AA::BB::CC as input returns CC and creates the namespace AA then inner - * namespace BB in the current scope. If no scope separator (::) in the input, then nothing happens! */ -static String *resolve_node_scope(String *cname) { + * namespace BB in the current scope. If cname is found to already exist as a weak symbol + * (forward reference) then the scope might be changed to match, such as when a symbol match + * is made via a using reference. */ +static String *resolve_create_node_scope(String *cname) { Symtab *gscope = 0; + Node *cname_node = 0; + int skip_lookup = 0; nscope = 0; nscope_inner = 0; + + if (Swig_scopename_check(cname)) { + String *prefix = Swig_scopename_prefix(cname); + if (prefix && (Strncmp(prefix,"::",2) == 0)) + skip_lookup = 1; + } + cname_node = skip_lookup ? 0 : Swig_symbol_clookup_no_inherit(cname, 0); + + if (cname_node) { + /* The symbol has been defined already or is in another scope. + If it is a weak symbol, it needs replacing and if it was brought into the current scope + via a using declaration, the scope needs adjusting appropriately for the new symbol. */ + Symtab *symtab = Getattr(cname_node, "sym:symtab"); + Node *sym_weak = Getattr(cname_node, "sym:weak"); + if (symtab && sym_weak) { + /* Check if the scope is the current scope */ + String *current_scopename = Swig_symbol_qualifiedscopename(0); + String *found_scopename = Swig_symbol_qualifiedscopename(symtab); + int len; + if (!current_scopename) + current_scopename = NewString(""); + if (!found_scopename) + found_scopename = NewString(""); + len = Len(current_scopename); + if ((len > 0) && (Strncmp(current_scopename, found_scopename, len) == 0)) { + if (Len(found_scopename) > len + 2) { + /* A matching weak symbol was found in non-global scope, some scope adjustment may be required */ + String *new_cname = NewString(Char(found_scopename) + len + 2); /* skip over "::" prefix */ + String *base = Swig_scopename_last(cname); + Printf(new_cname, "::%s", base); + cname = new_cname; + Delete(base); + } else { + /* A matching weak symbol was found in the same non-global local scope, no scope adjustment required */ + assert(len == Len(found_scopename)); + } + } else { + String *base = Swig_scopename_last(cname); + if (Len(found_scopename) > 0) { + /* A matching weak symbol was found in a different scope to the local scope - probably via a using declaration */ + cname = NewStringf("%s::%s", found_scopename, base); + } else { + /* Either: + 1) A matching weak symbol was found in a different scope to the local scope - this is actually a + symbol with the same name in a different scope which we don't want, so no adjustment required. + 2) A matching weak symbol was found in the global scope - no adjustment required. + */ + cname = Copy(base); + } + Delete(base); + } + Delete(current_scopename); + Delete(found_scopename); + } + } + if (Swig_scopename_check(cname)) { Node *ns; String *prefix = Swig_scopename_prefix(cname); String *base = Swig_scopename_last(cname); if (prefix && (Strncmp(prefix,"::",2) == 0)) { +/* I don't think we can use :: global scope to declare classes and hence neither %template. - consider reporting error instead - wsfulton. */ /* Use the global scope */ String *nprefix = NewString(Char(prefix)+2); Delete(prefix); prefix= nprefix; gscope = set_scope_to_global(); - } - if (!prefix || (Len(prefix) == 0)) { + } + if (Len(prefix) == 0) { /* Use the global scope, but we need to add a 'global' namespace. */ if (!gscope) gscope = set_scope_to_global(); /* note that this namespace is not the "unnamed" one, @@ -904,8 +964,7 @@ static String *resolve_node_scope(String *cname) { } else { Symtab *nstab = Getattr(ns,"symtab"); if (!nstab) { - Swig_error(cparse_file,cparse_line, - "'%s' is not defined as a valid scope.\n", prefix); + Swig_error(cparse_file,cparse_line, "'%s' is not defined as a valid scope.\n", prefix); ns = 0; } else { /* Check if the node scope is the current scope */ @@ -986,6 +1045,7 @@ static String *resolve_node_scope(String *cname) { } Delete(prefix); } + return cname; } @@ -2784,7 +2844,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va /* If the class name is qualified, we need to create or lookup namespace entries */ if (!inclass) { - $5 = resolve_node_scope($5); + $5 = resolve_create_node_scope($5); } /* @@ -3406,7 +3466,7 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { prev_symtab = Swig_symbol_current(); /* If the class name is qualified. We need to create or lookup namespace/scope entries */ - scope = resolve_node_scope($3); + scope = resolve_create_node_scope($3); Setfile(scope,cparse_file); Setline(scope,cparse_line); $3 = scope; diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h index 97b730508..a85334e55 100644 --- a/Source/Swig/swig.h +++ b/Source/Swig/swig.h @@ -227,6 +227,7 @@ extern "C" { extern void Swig_symbol_cadd(const_String_or_char_ptr symname, Node *node); extern Node *Swig_symbol_clookup(const_String_or_char_ptr symname, Symtab *tab); extern Node *Swig_symbol_clookup_check(const_String_or_char_ptr symname, Symtab *tab, int (*check) (Node *)); + extern Node *Swig_symbol_clookup_no_inherit(const_String_or_char_ptr name, Symtab *n); extern Symtab *Swig_symbol_cscope(const_String_or_char_ptr symname, Symtab *tab); extern Node *Swig_symbol_clookup_local(const_String_or_char_ptr symname, Symtab *tab); extern Node *Swig_symbol_clookup_local_check(const_String_or_char_ptr symname, Symtab *tab, int (*check) (Node *)); diff --git a/Source/Swig/symbol.c b/Source/Swig/symbol.c index 0cf6cdb53..e9565c9da 100644 --- a/Source/Swig/symbol.c +++ b/Source/Swig/symbol.c @@ -176,6 +176,8 @@ static Hash *current_symtab = 0; /* Current symbol table node */ static Hash *symtabs = 0; /* Hash of all symbol tables by fully-qualified name */ static Hash *global_scope = 0; /* Global scope */ +static int use_inherit = 1; + /* common attribute keys, to avoid calling find_key all the times */ @@ -482,9 +484,9 @@ void Swig_symbol_alias(const_String_or_char_ptr aliasname, Symtab *s) { /* ----------------------------------------------------------------------------- * Swig_symbol_inherit() * - * Inherit symbols from another scope. - * Primarily for using directives, such as 'using namespace X;'. - * Not for using declarations, such as 'using A;'. + * Inherit symbols from another scope. Primarily for C++ inheritance and + * for using directives, such as 'using namespace X;' + * but not for using declarations, such as 'using A;'. * ----------------------------------------------------------------------------- */ void Swig_symbol_inherit(Symtab *s) { @@ -970,7 +972,7 @@ static Node *_symbol_lookup(const String *name, Symtab *symtab, int (*check) (No } inherit = Getattr(symtab, "inherit"); - if (inherit) { + if (inherit && use_inherit) { int i, len; len = Len(inherit); for (i = 0; i < len; i++) { @@ -1060,7 +1062,7 @@ static Node *symbol_lookup_qualified(const_String_or_char_ptr name, Symtab *symt /* Check inherited scopes */ if (!n) { List *inherit = Getattr(symtab, "inherit"); - if (inherit) { + if (inherit && use_inherit) { int i, len; len = Len(inherit); for (i = 0; i < len; i++) { @@ -1327,6 +1329,11 @@ Node *Swig_symbol_clookup_local_check(const_String_or_char_ptr name, Symtab *n, return s; } +Node *Swig_symbol_clookup_no_inherit(const_String_or_char_ptr name, Symtab *n) { + use_inherit = 0; + Swig_symbol_clookup(name, n); + use_inherit = 1; +} /* ----------------------------------------------------------------------------- * Swig_symbol_cscope()