diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index 67f0c3965..3d9f6fd3b 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -253,6 +253,7 @@
  • Template base classes
  • Template specialization
  • Member templates +
  • Scoping and templates
  • More on templates
  • Namespaces diff --git a/Doc/Manual/SWIGPlus.html b/Doc/Manual/SWIGPlus.html index 7cc0d5387..13c81588d 100644 --- a/Doc/Manual/SWIGPlus.html +++ b/Doc/Manual/SWIGPlus.html @@ -56,6 +56,7 @@
  • Template base classes
  • Template specialization
  • Member templates +
  • Scoping and templates
  • More on templates
  • Namespaces @@ -3599,7 +3600,108 @@ constructor, that will dispatch the proper call depending on the argument type.

    -

    6.18.7 More on templates

    +

    6.18.7 Scoping and templates

    + + +

    +The %template directive for a class template is the equivalent to an explicit instantiation +of a C++ class template. The scope for a valid %template instantiation is the same +as the scope required for a valid explicit instantiation of a C++ template. +A definition of the template for the explicit instantiation must be in scope +where the instantiation is declared and must not be enclosed within a different namespace. +

    + +

    +For example, a few %template instantiations and C++ explicit instantiations are shown below: +

    + +
    +
    +namespace N {
    +  template<typename T> class C {};
    +}
    +
    +// valid
    +%template(cin) N::C<int>;
    +template class N::C<int>;
    +
    +// valid
    +namespace N {
    +  %template(cin) C<int>;
    +  template class C<int>;
    +}
    +
    +// valid
    +using namespace N;
    +%template(cin) C<int>;
    +template class C<int>;
    +
    +// valid
    +using N::C;
    +%template(cin) C<int>;
    +template class C<int>;
    +
    +// ill-formed
    +namespace unrelated {
    +  using N::C;
    +  %template(cin) C<int>;
    +  template class C<int>;
    +}
    +
    +// ill-formed
    +namespace unrelated {
    +  using namespace N;
    +  %template(cin) C<int>;
    +  template class C<int>;
    +}
    +
    +// ill-formed
    +namespace unrelated {
    +  namespace N {
    +    %template(cin) C<int>;
    +    template class C<int>;
    +  }
    +}
    +
    +// ill-formed
    +namespace unrelated {
    +  %template(cin) N::C<int>;
    +  template class N::C<int>;
    +}
    +
    +
    + +

    +When the scope is incorrect, such as for the ill-formed examples above, an error occurs: +

    + +
    +
    +cpp_template_scope.i:34: Error: 'C' resolves to 'N::C' and was incorrectly instantiated
    +in scope 'unrelated' instead of within scope 'N'.
    +
    +
    + +

    +A note for the C++ standard geeks out there; a valid instantiation is one which conforms to +the C++03 standard as C++11 made a change to disallow using declarations and using directives to find a template. +

    + +
    +
    +// valid C++03, ill-formed C++11
    +using N::C;
    +template class C<int>;
    +
    +
    + +

    +Compatibility Note: Versions prior to SWIG-4.0.0 did not error out with incorrectly scoped +%template declarations, but this led to numerous subtle template scope problems. +

    + + +

    6.18.8 More on templates

    @@ -4348,9 +4450,9 @@ In the example below, the generic template type is used to rename to bbb

    -%rename(bbb) Space::ABC::aaa(T t);                  // will match but with lower precedence than ccc
    +%rename(bbb) Space::ABC::aaa(T t);                     // will match but with lower precedence than ccc
     %rename(ccc) Space::ABC<Space::XYZ>::aaa(Space::XYZ t);// will match but with higher precedence
    -                                                             // than bbb
    +                                                       // than bbb
     
     namespace Space {
       class XYZ {};
    diff --git a/Examples/test-suite/class_scope_namespace.i b/Examples/test-suite/class_scope_namespace.i
    new file mode 100644
    index 000000000..08a9f01dc
    --- /dev/null
    +++ b/Examples/test-suite/class_scope_namespace.i
    @@ -0,0 +1,153 @@
    +// Test a mix of forward class declarations, class definitions, using declarations and using directives.
    +
    +%module class_scope_namespace
    +
    +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) H::HH;
    +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Space8::I::II;
    +
    +%inline %{
    +struct A;
    +namespace Space1 {
    +  namespace SubSpace1 {
    +    struct A {
    +      void aa(Space1::SubSpace1::A, SubSpace1::A, A) {}
    +    };
    +    void aaa(Space1::SubSpace1::A, SubSpace1::A, A) {}
    +  }
    +}
    +
    +namespace Space2 {
    +  struct B;
    +}
    +using Space2::B;
    +struct B {
    +  void bb(Space2::B, B) {}
    +};
    +void bbb(Space2::B, B) {}
    +
    +namespace Space3 {
    +  namespace SubSpace3 {
    +    struct C;
    +    struct D;
    +  }
    +}
    +struct C;
    +struct D;
    +namespace Space3 {
    +  struct C;
    +  struct SubSpace3::C {
    +    void cc(Space3::SubSpace3::C, SubSpace3::C) {}
    +  };
    +  using SubSpace3::D;
    +  struct SubSpace3::D {
    +    void dd(Space3::SubSpace3::D, SubSpace3::D, D) {}
    +  };
    +  void ccc(Space3::SubSpace3::C, SubSpace3::C) {}
    +  void ddd(Space3::SubSpace3::D, SubSpace3::D, D) {}
    +}
    +
    +namespace Space4 {
    +  namespace SubSpace4 {
    +    struct E;
    +  }
    +}
    +using namespace Space4;
    +using SubSpace4::E;
    +// Was added to incorrect namespace in swig-3.0.12
    +struct SubSpace4::E {
    +  void ee(Space4::SubSpace4::E, SubSpace4::E, E) {}
    +};
    +void eee(Space4::SubSpace4::E, SubSpace4::E, E) {}
    +
    +namespace Space5 {
    +  namespace SubSpace5 {
    +    namespace SubSubSpace5 {
    +      struct F;
    +    }
    +  }
    +}
    +namespace Space5 {
    +  using namespace SubSpace5;
    +  using SubSubSpace5::F;
    +  // Was added to incorrect namespace in swig-3.0.12
    +  struct SubSubSpace5::F {
    +    void ff(Space5::SubSpace5::SubSubSpace5::F, SubSpace5::SubSubSpace5::F, SubSubSpace5::F, F) {}
    +  };
    +// needs fixing
    +  void fff(Space5::SubSpace5::SubSubSpace5::F, SubSpace5::SubSubSpace5::F, /*SubSubSpace5::F,*/ F) {}
    +}
    +
    +namespace Space6 {
    +  struct G;
    +  namespace SubSpace6 {
    +    struct G;
    +  }
    +}
    +namespace Space6 {
    +  struct SubSpace6::G {
    +    void gg(Space6::SubSpace6::G, SubSpace6::G) {}
    +  };
    +  void ggg(Space6::SubSpace6::G, SubSpace6::G) {}
    +}
    +
    +struct HH;
    +struct H {
    +  struct HH {
    +    void hh(H::HH) {}
    +  };
    +};
    +void hhh(H::HH) {}
    +
    +namespace Space8 {
    +  struct II;
    +  struct I {
    +    struct II {
    +      void ii(Space8::I::II, I::II) {}
    +    };
    +  };
    +  void iii(Space8::I::II, I::II) {}
    +}
    +
    +struct J;
    +namespace Space9 {
    +  namespace SubSpace9 {
    +    struct J {
    +      void jj(Space9::SubSpace9::J, SubSpace9::J, J) {}
    +    };
    +    void jjj(Space9::SubSpace9::J, SubSpace9::J, J) {}
    +  }
    +}
    +
    +namespace Space10 {
    +  struct K;
    +}
    +namespace Space10 {
    +  namespace SubSpace10 {
    +    struct K {
    +      void kk(Space10::SubSpace10::K, SubSpace10::K, K) {}
    +    };
    +    void kkk(Space10::SubSpace10::K, SubSpace10::K, K) {}
    +  }
    +}
    +
    +namespace OtherSpace {
    +  struct L;
    +  struct M;
    +}
    +using OtherSpace::L;
    +namespace Space11 {
    +  using OtherSpace::M;
    +  namespace SubSpace11 {
    +    struct L {
    +      void ll(Space11::SubSpace11::L, SubSpace11::L, L) {}
    +    };
    +    void lll(Space11::SubSpace11::L, SubSpace11::L, L) {}
    +    struct M {
    +      void mm(Space11::SubSpace11::M, SubSpace11::M, M) {}
    +    };
    +    void mmm(Space11::SubSpace11::M, SubSpace11::M, M) {}
    +  }
    +}
    +
    +%}
    +
    diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk
    index ab341e7a1..0c896825f 100644
    --- a/Examples/test-suite/common.mk
    +++ b/Examples/test-suite/common.mk
    @@ -136,6 +136,7 @@ CPP_TEST_CASES += \
     	char_binary \
     	char_strings \
     	chartest \
    +	class_scope_namespace \
     	class_forward \
     	class_ignore \
     	class_scope_weird \
    diff --git a/Examples/test-suite/errors/cpp_class_definition.i b/Examples/test-suite/errors/cpp_class_definition.i
    new file mode 100644
    index 000000000..8381e75cc
    --- /dev/null
    +++ b/Examples/test-suite/errors/cpp_class_definition.i
    @@ -0,0 +1,26 @@
    +%module xxx
    +
    +// This should error but doesn't
    +#if 0
    +namespace OtherSpace {
    +  struct L;
    +}
    +namespace Space11 {
    +  namespace SubSpace11 {
    +    using OtherSpace::L;
    +    struct L {
    +      void ll();
    +    };
    +  }
    +}
    +#endif
    +
    +namespace Space1 {
    +  struct A;
    +}
    +namespace Space2 {
    +  struct Space1::A {
    +    void x();
    +  };
    +}
    +
    diff --git a/Examples/test-suite/errors/cpp_class_definition.stderr b/Examples/test-suite/errors/cpp_class_definition.stderr
    new file mode 100644
    index 000000000..2c4102842
    --- /dev/null
    +++ b/Examples/test-suite/errors/cpp_class_definition.stderr
    @@ -0,0 +1 @@
    +cpp_class_definition.i:22: Error: 'Space1::A' resolves to 'Space1::A' and was incorrectly instantiated in scope 'Space2' instead of within scope 'Space1'.
    diff --git a/Examples/test-suite/errors/cpp_namespace_template_bad.i b/Examples/test-suite/errors/cpp_namespace_template_bad.i
    new file mode 100644
    index 000000000..5c42d6dcb
    --- /dev/null
    +++ b/Examples/test-suite/errors/cpp_namespace_template_bad.i
    @@ -0,0 +1,40 @@
    +%module namespace_template
    +
    +namespace test {
    +  template T max(T a, T b) { return (a > b) ? a : b; }
    +  template class vector { 
    +  public:
    +    vector() { }
    +    ~vector() { }
    +  }; 
    +}
    +
    +namespace test2 {
    +  using namespace test;
    +  %template(maxshort) max;
    +  %template(vectorshort) vector;
    +}
    +
    +namespace test3 {
    +  using test::max;
    +  using test::vector;
    +  %template(maxlong) max;
    +  %template(vectorlong) vector;
    +}
    +
    +namespace test4 {
    +  using namespace test;
    +  typedef int Integer;
    +}
    +
    +namespace test4 {
    +  %template(maxInteger) max;
    +  %template(vectorInteger) vector;
    +}
    +
    +using namespace test;
    +namespace test5 {
    +  %template(maxdouble) max;
    +  %template(vectordouble) vector;
    +}
    +
    diff --git a/Examples/test-suite/errors/cpp_namespace_template_bad.stderr b/Examples/test-suite/errors/cpp_namespace_template_bad.stderr
    new file mode 100644
    index 000000000..5965d529c
    --- /dev/null
    +++ b/Examples/test-suite/errors/cpp_namespace_template_bad.stderr
    @@ -0,0 +1,9 @@
    +cpp_namespace_template_bad.i:14: Error: 'max' resolves to 'test::max' and was incorrectly instantiated in scope 'test2' instead of within scope 'test'.
    +cpp_namespace_template_bad.i:15: Error: 'vector' resolves to 'test::vector' and was incorrectly instantiated in scope 'test2' instead of within scope 'test'.
    +cpp_namespace_template_bad.i:21: Error: 'max' resolves to 'test::max' and was incorrectly instantiated in scope 'test3' instead of within scope 'test'.
    +cpp_namespace_template_bad.i:22: Error: 'vector' resolves to 'test::vector' and was incorrectly instantiated in scope 'test3' instead of within scope 'test'.
    +cpp_namespace_template_bad.i:31: Error: 'max' resolves to 'test::max' and was incorrectly instantiated in scope 'test4' instead of within scope 'test'.
    +cpp_namespace_template_bad.i:32: Error: 'vector' resolves to 'test::vector' and was incorrectly instantiated in scope 'test4' instead of within scope 'test'.
    +cpp_namespace_template_bad.i:37: Error: 'max' resolves to 'test::max' and was incorrectly instantiated in scope 'test5' instead of within scope 'test'.
    +cpp_namespace_template_bad.i:37: Error: Template 'max' undefined.
    +cpp_namespace_template_bad.i:38: Error: 'vector' resolves to 'test::vector' and was incorrectly instantiated in scope 'test5' instead of within scope 'test'.
    diff --git a/Examples/test-suite/errors/cpp_nested_template.stderr b/Examples/test-suite/errors/cpp_nested_template.stderr
    index 9e46cff74..363a260f6 100644
    --- a/Examples/test-suite/errors/cpp_nested_template.stderr
    +++ b/Examples/test-suite/errors/cpp_nested_template.stderr
    @@ -1,2 +1,4 @@
    +cpp_nested_template.i:9: Error: 'Temply' resolves to '::Temply' and was incorrectly instantiated in scope 'A' instead of within scope ''.
     cpp_nested_template.i:9: Warning 324: Named nested template instantiations not supported. Processing as if no name was given to %template().
    +cpp_nested_template.i:18: Error: 'Temply' resolves to '::Temply' and was incorrectly instantiated in scope 'B' instead of within scope ''.
     cpp_nested_template.i:18: Warning 324: Named nested template instantiations not supported. Processing as if no name was given to %template().
    diff --git a/Examples/test-suite/errors/cpp_template_scope.i b/Examples/test-suite/errors/cpp_template_scope.i
    new file mode 100644
    index 000000000..ec0f0a577
    --- /dev/null
    +++ b/Examples/test-suite/errors/cpp_template_scope.i
    @@ -0,0 +1,57 @@
    +%module xxx
    +
    +namespace std {
    +  template class vector {};
    +}
    +
    +struct S1 {};
    +struct S2 {};
    +struct S3 {};
    +struct S4 {};
    +struct S5 {};
    +struct S6 {};
    +struct S7 {};
    +
    +// valid
    +namespace std {
    +  %template(vi1) vector;
    +  template class vector;
    +}
    +
    +// valid
    +using namespace std;
    +%template(vi2) vector;
    +template class vector;
    +
    +// valid
    +using std::vector;
    +%template(vi3) vector;
    +template class vector;
    +
    +// ill-formed
    +namespace unrelated {
    +  using std::vector;
    +  %template(vi4) vector;
    +  template class vector;
    +}
    +
    +// ill-formed
    +namespace unrelated {
    +  using namespace std;
    +  %template(vi5) vector;
    +  template class vector;
    +}
    +
    +// ill-formed
    +namespace unrelated {
    +  namespace std {
    +    %template(vi6) vector;
    +    template class vector;
    +  }
    +}
    +
    +// ill-formed
    +namespace unrelated {
    +  %template(vi7) std::vector;
    +  template class std::vector;
    +}
    diff --git a/Examples/test-suite/errors/cpp_template_scope.stderr b/Examples/test-suite/errors/cpp_template_scope.stderr
    new file mode 100644
    index 000000000..e47630268
    --- /dev/null
    +++ b/Examples/test-suite/errors/cpp_template_scope.stderr
    @@ -0,0 +1,11 @@
    +cpp_template_scope.i:18: Warning 320: Explicit template instantiation ignored.
    +cpp_template_scope.i:24: Warning 320: Explicit template instantiation ignored.
    +cpp_template_scope.i:29: Warning 320: Explicit template instantiation ignored.
    +cpp_template_scope.i:34: Error: 'vector' resolves to 'std::vector' and was incorrectly instantiated in scope 'unrelated' instead of within scope 'std'.
    +cpp_template_scope.i:35: Warning 320: Explicit template instantiation ignored.
    +cpp_template_scope.i:41: Error: 'vector' resolves to 'std::vector' and was incorrectly instantiated in scope 'unrelated' instead of within scope 'std'.
    +cpp_template_scope.i:42: Warning 320: Explicit template instantiation ignored.
    +cpp_template_scope.i:48: Error: 'vector' resolves to 'std::vector' and was incorrectly instantiated in scope 'unrelated::std' instead of within scope 'std'.
    +cpp_template_scope.i:49: Warning 320: Explicit template instantiation ignored.
    +cpp_template_scope.i:55: Error: 'std::vector' resolves to 'std::vector' and was incorrectly instantiated in scope 'unrelated' instead of within scope 'std'.
    +cpp_template_scope.i:56: Warning 320: Explicit template instantiation ignored.
    diff --git a/Examples/test-suite/java/class_scope_namespace_runme.java b/Examples/test-suite/java/class_scope_namespace_runme.java
    new file mode 100644
    index 000000000..e80779413
    --- /dev/null
    +++ b/Examples/test-suite/java/class_scope_namespace_runme.java
    @@ -0,0 +1,59 @@
    +
    +import class_scope_namespace.*;
    +
    +public class class_scope_namespace_runme {
    +
    +  static {
    +    try {
    +      System.loadLibrary("class_scope_namespace");
    +    } 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[]) 
    +  {
    +    A a = new A();
    +    B b = new B();
    +    C c = new C();
    +    D d = new D();
    +    E e = new E();
    +    F f = new F();
    +    G g = new G();
    +    H.HH h = new H.HH();
    +    I.II i = new I.II();
    +    J j = new J();
    +    K k = new K();
    +    L l = new L();
    +    M m = new M();
    +
    +    a.aa(a, a, a);
    +    b.bb(b, b);
    +    c.cc(c, c);
    +    d.dd(d, d, d);
    +    e.ee(e, e, e);
    +    f.ff(f, f, f, f);
    +    g.gg(g, g);
    +    h.hh(h);
    +    i.ii(i, i);
    +    j.jj(j, j, j);
    +    k.kk(k, k, k);
    +    l.ll(l, l, l);
    +    m.mm(m, m, m);
    +
    +    class_scope_namespace.aaa(a, a, a);
    +    class_scope_namespace.bbb(b, b);
    +    class_scope_namespace.ccc(c, c);
    +    class_scope_namespace.ddd(d, d, d);
    +    class_scope_namespace.eee(e, e, e);
    +    class_scope_namespace.fff(f, f, f);
    +    class_scope_namespace.ggg(g, g);
    +    class_scope_namespace.hhh(h);
    +    class_scope_namespace.iii(i, i);
    +    class_scope_namespace.jjj(j, j, j);
    +    class_scope_namespace.kkk(k, k, k);
    +    class_scope_namespace.lll(l, l, l);
    +    class_scope_namespace.mmm(m, m, m);
    +  }
    +}
    diff --git a/Examples/test-suite/java/namespace_template_runme.java b/Examples/test-suite/java/namespace_template_runme.java
    new file mode 100644
    index 000000000..c0c7ba135
    --- /dev/null
    +++ b/Examples/test-suite/java/namespace_template_runme.java
    @@ -0,0 +1,32 @@
    +
    +import namespace_template.*;
    +
    +public class namespace_template_runme {
    +
    +  static {
    +    try {
    +      System.loadLibrary("namespace_template");
    +    } 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[]) {
    +    vectorchar vc = new vectorchar();
    +    vectorshort vs = new vectorshort();
    +    vectorint vi = new vectorint();
    +    vectorlong vl = new vectorlong();
    +
    +    vc.blah((char)10);
    +    vs.blah((short)10);
    +    vi.blah(10);
    +    vl.blah(10);
    +
    +    vc.vectoruse(vc, vc);
    +    vs.vectoruse(vs, vs);
    +    vi.vectoruse(vi, vi);
    +    vl.vectoruse(vl, vl);
    +  }
    +}
    +
    diff --git a/Examples/test-suite/namespace_template.i b/Examples/test-suite/namespace_template.i
    index a36abb19b..8a4b6dca9 100644
    --- a/Examples/test-suite/namespace_template.i
    +++ b/Examples/test-suite/namespace_template.i
    @@ -2,10 +2,10 @@
     
     %module namespace_template
     
    -%warnfilter(SWIGWARN_RUBY_WRONG_NAME) vector;            /* Ruby, wrong class name */
    -%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test2::vector;   /* Ruby, wrong class name */
    -%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test3::vector;    /* Ruby, wrong class name */
    -%warnfilter(SWIGWARN_RUBY_WRONG_NAME) vector; /* Ruby, wrong class name */
    +%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector;        /* Ruby, wrong class name */
    +%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector;      /* Ruby, wrong class name */
    +%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector;       /* Ruby, wrong class name */
    +%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector; /* Ruby, wrong class name */
     
     %{
     #ifdef max
    @@ -23,20 +23,9 @@ namespace test {
                char * blah(T x) {
                   return (char *) "vector::blah";
                }
    +           void vectoruse(vector a, test::vector b) {}
        }; 
     }
    -
    -namespace test2 {
    -   using namespace test;
    -}
    -
    -namespace test3 {
    -   using test::max;
    -   using test::vector;
    -}
    -
    -using namespace test2;
    -namespace T4 = test;
     %}
     
     namespace test {
    @@ -48,6 +37,7 @@ namespace test {
                char * blah(T x) {
                   return (char *) "vector::blah";
                }
    +           void vectoruse(vector a, test::vector b) {}
        }; 
     }
     
    @@ -55,30 +45,26 @@ using namespace test;
     %template(maxint) max;
     %template(vectorint) vector;
     
    -namespace test2 {
    -   using namespace test;
    +namespace test {
        %template(maxshort) max;
        %template(vectorshort) vector;
     }
     
    -namespace test3 {
    -   using test::max;
    -   using test::vector;
    +namespace test {
        %template(maxlong) max;
        %template(vectorlong) vector;
     }
     
     %inline %{
     
    -namespace test4 {
    -   using namespace test;
    -   typedef int Integer;
    +namespace test {
    +   typedef char Char;
     }
     
     %}
     
    -namespace test4 {
    -   %template(maxInteger) max;
    -   %template(vectorInteger) vector;
    +namespace test {
    +   %template(maxchar) max;
    +   %template(vectorchar) vector;
     }
     
    diff --git a/Examples/test-suite/smart_pointer_namespace2.i b/Examples/test-suite/smart_pointer_namespace2.i
    index 882799862..e78364c25 100644
    --- a/Examples/test-suite/smart_pointer_namespace2.i
    +++ b/Examples/test-suite/smart_pointer_namespace2.i
    @@ -49,11 +49,6 @@ namespace one
         };
     }
     
    -%define PTR_DEF(o)
    -typedef one::Ptr o ## _ptr;
    -%template(o ## _ptr) one::Ptr;
    -%enddef
    -
     namespace one
     {
         class Obj1
    @@ -63,7 +58,8 @@ namespace one
             void donothing() {}
         };
     
    -    PTR_DEF(Obj1)
    +    typedef one::Ptr Obj1_ptr;
    +    %template(Obj1_ptr) one::Ptr;
     }
     
     namespace two
    @@ -75,6 +71,9 @@ namespace two
             void donothing() {}
         };
     
    -    PTR_DEF(Obj2)
    +    typedef one::Ptr Obj2_ptr;
     }
     
    +using two::Obj2;
    +%template(Obj2_ptr) one::Ptr;
    +
    diff --git a/Examples/test-suite/template_nested_typemaps.i b/Examples/test-suite/template_nested_typemaps.i
    index 54f5bc503..577a88e14 100644
    --- a/Examples/test-suite/template_nested_typemaps.i
    +++ b/Examples/test-suite/template_nested_typemaps.i
    @@ -1,25 +1,30 @@
    -#pragma SWIG nowarn=SWIGWARN_PARSE_NESTED_TEMPLATE
    -
     %module template_nested_typemaps
     
    -// Testing that the typemaps invoked within a class via %template are picked up by appropriate methods
    +#pragma SWIG nowarn=SWIGWARN_PARSE_NAMED_NESTED_CLASS
     
    -template  struct Typemap {
    -  %typemap(in) T {
    -    $1 = -99;
    -  }
    -};
    -template <> struct Typemap { // Note explicit specialization
    -  %typemap(in) short {
    -    $1 = -77;
    -  }
    -};
    +// Testing that the typemaps invoked within a class via %template are picked up by appropriate methods
    +// Only for languages that support nested classes
     
     %inline %{
     int globalInt1(int s) { return s; }
     short globalShort1(short s) { return s; }
     
     template  struct Breeze {
    +  template  struct Typemap {
    +#ifdef SWIG
    +    %typemap(in) TMT {
    +      $1 = -99;
    +    }
    +#endif
    +  };
    +  template  struct TypemapShort {
    +#ifdef SWIG
    +    %typemap(in) short {
    +      $1 = -77;
    +    }
    +#endif
    +  };
    +
       int methodInt1(int s) { return s; }
     #if defined(SWIG)
       %template() Typemap;
    @@ -29,7 +34,7 @@ template  struct Breeze {
     
       short methodShort1(short s) { return s; }
     #if defined(SWIG)
    -  %template(TypemapShort) Typemap; // should issue warning SWIGWARN_PARSE_NESTED_TEMPLATE
    +  %template() TypemapShort;
     #endif
       short methodShort2(short s) { return s; } // should pick up the typemap within Typemap
     };
    diff --git a/Examples/test-suite/template_partial_specialization.i b/Examples/test-suite/template_partial_specialization.i
    index 8781fbbda..a7afd3000 100644
    --- a/Examples/test-suite/template_partial_specialization.i
    +++ b/Examples/test-suite/template_partial_specialization.i
    @@ -32,7 +32,7 @@ namespace One {
     %template(H) One::OneParm;
     
     // %template scope explicit specializations
    -namespace ONE {
    +namespace One {
       %template(I) One::OneParm;
       %template(J) ::One::OneParm;
     }
    @@ -42,7 +42,7 @@ namespace One {
     }
     
     // %template scope partial specializations
    -namespace ONE {
    +namespace One {
       %template(BB) One::OneParm;
       %template(BBB) ::One::OneParm;
     }
    diff --git a/Examples/test-suite/template_partial_specialization_typedef.i b/Examples/test-suite/template_partial_specialization_typedef.i
    index 6fdbf99aa..9c00efc98 100644
    --- a/Examples/test-suite/template_partial_specialization_typedef.i
    +++ b/Examples/test-suite/template_partial_specialization_typedef.i
    @@ -59,7 +59,7 @@ namespace One {
     %template(H) One::OneParm;
     
     // %template scope explicit specializations
    -namespace ONE {
    +namespace One {
       %template(I) One::OneParm;
       %template(J) ::One::OneParm;
     }
    @@ -69,7 +69,7 @@ namespace One {
     }
     
     // %template scope partial specializations
    -namespace ONE {
    +namespace One {
       %template(BB) One::OneParm;
       %template(BBB) ::One::OneParm;
     }
    diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
    index 69dce5534..30408e73b 100644
    --- a/Source/CParse/parser.y
    +++ b/Source/CParse/parser.y
    @@ -209,7 +209,7 @@ static String *yyrename = 0;
     
     /* Forward renaming operator */
     
    -static String *resolve_create_node_scope(String *cname);
    +static String *resolve_create_node_scope(String *cname, int is_class_definition);
     
     
     Hash *Swig_cparse_features(void) {
    @@ -815,32 +815,53 @@ static String *remove_block(Node *kw, const String *inputcode) {
       return modified_code;
     }
     
    -
    +/*
    +#define RESOLVE_DEBUG 1
    +*/
     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 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 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) {
    + * namespace BB in the current scope. */
    +static String *resolve_create_node_scope(String *cname, int is_class_definition) {
       Symtab *gscope = 0;
       Node *cname_node = 0;
    -  int skip_lookup = 0;
    +  String *last = Swig_scopename_last(cname);
       nscope = 0;
       nscope_inner = 0;  
     
    -  if (Strncmp(cname,"::",2) == 0)
    -    skip_lookup = 1;
    -
    -  cname_node = skip_lookup ? 0 : Swig_symbol_clookup_no_inherit(cname, 0);
    +  if (Strncmp(cname,"::" ,2) != 0) {
    +    if (is_class_definition) {
    +      /* Only lookup symbols which are in scope via a using declaration but not via a using directive.
    +         For example find y via 'using x::y' but not y via a 'using namespace x'. */
    +      cname_node = Swig_symbol_clookup_no_inherit(cname, 0);
    +      if (!cname_node) {
    +	Node *full_lookup_node = Swig_symbol_clookup(cname, 0);
    +	if (full_lookup_node) {
    +	 /* This finds a symbol brought into scope via both a using directive and a using declaration. */
    +	  Node *last_node = Swig_symbol_clookup_no_inherit(last, 0);
    +	  if (last_node == full_lookup_node)
    +	    cname_node = last_node;
    +	}
    +      }
    +    } else {
    +      /* For %template, the template needs to be in scope via any means. */
    +      cname_node = Swig_symbol_clookup(cname, 0);
    +    }
    +  }
    +#if RESOLVE_DEBUG
    +  if (!cname_node)
    +    Printf(stdout, "symbol does not yet exist (%d): [%s]\n", is_class_definition, cname);
    +  else
    +    Printf(stdout, "symbol does exist (%d): [%s]\n", is_class_definition, cname);
    +#endif
     
       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.
    +       If it is a weak symbol, it needs replacing and if it was brought into the current scope,
    +       the scope needs adjusting appropriately for the new symbol.
            Similarly for defined templates. */
         Symtab *symtab = Getattr(cname_node, "sym:symtab");
         Node *sym_weak = Getattr(cname_node, "sym:weak");
    @@ -848,48 +869,92 @@ static String *resolve_create_node_scope(String *cname) {
           /* 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));
    +
    +      {
    +	int fail = 1;
    +	List *current_scopes = Swig_scopename_tolist(current_scopename);
    +	List *found_scopes = Swig_scopename_tolist(found_scopename);
    +        Iterator cit = First(current_scopes);
    +	Iterator fit = First(found_scopes);
    +#if RESOLVE_DEBUG
    +Printf(stdout, "comparing current: [%s] found: [%s]\n", current_scopename, found_scopename);
    +#endif
    +	for (; fit.item && cit.item; fit = Next(fit), cit = Next(cit)) {
    +	  String *current = cit.item;
    +	  String *found = fit.item;
    +#if RESOLVE_DEBUG
    +	  Printf(stdout, "  looping %s %s\n", current, found);
    +#endif
    +	  if (Strcmp(current, found) != 0)
    +	    break;
     	}
    -      } 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);
    +
    +	if (!cit.item) {
    +	  String *subscope = NewString("");
    +	  for (; fit.item; fit = Next(fit)) {
    +	    if (Len(subscope) > 0)
    +	      Append(subscope, "::");
    +	    Append(subscope, fit.item);
    +	  }
    +	  if (Len(subscope) > 0)
    +	    cname = NewStringf("%s::%s", subscope, last);
    +	  else
    +	    cname = Copy(last);
    +#if RESOLVE_DEBUG
    +	  Printf(stdout, "subscope to create: [%s] cname: [%s]\n", subscope, cname);
    +#endif
    +	  fail = 0;
    +	  Delete(subscope);
     	} 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);
    +	  if (is_class_definition) {
    +	    if (!fit.item) {
    +	      /* It is valid to define a new class with the same name as one forward declared in a parent scope */
    +	      fail = 0;
    +	    } else if (Swig_scopename_check(cname)) {
    +	      /* Classes defined with scope qualifiers must have a matching forward declaration in matching scope */
    +	      fail = 1;
    +	    } else {
    +	      /* This may let through some invalid cases */
    +	      fail = 0;
    +	    }
    +#if RESOLVE_DEBUG
    +	    Printf(stdout, "scope for class definition, fail: %d\n", fail);
    +#endif
    +	  } else {
    +#if RESOLVE_DEBUG
    +	    Printf(stdout, "no matching base scope for template\n");
    +#endif
    +	    fail = 1;
    +	  }
    +	}
    +
    +	Delete(found_scopes);
    +	Delete(current_scopes);
    +
    +	if (fail) {
    +	  String *cname_resolved = NewStringf("%s::%s", found_scopename, last);
    +	  Swig_error(cparse_file, cparse_line, "'%s' resolves to '%s' and was incorrectly instantiated in scope '%s' instead of within scope '%s'.\n", cname, cname_resolved, current_scopename, found_scopename);
    +	  cname = Copy(last);
    +	  Delete(cname_resolved);
     	}
    -	Delete(base);
           }
    +
           Delete(current_scopename);
           Delete(found_scopename);
         }
    +  } else if (!is_class_definition) {
    +    /* A template instantiation requires a template to be found in scope... fail here too?
    +    Swig_error(cparse_file, cparse_line, "No template found to instantiate '%s' with %%template.\n", cname);
    +     */
       }
     
       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 */
    @@ -899,6 +964,7 @@ static String *resolve_create_node_scope(String *cname) {
           gscope = set_scope_to_global();
         }
         if (Len(prefix) == 0) {
    +      String *base = Copy(last);
           /* 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,
    @@ -907,6 +973,7 @@ static String *resolve_create_node_scope(String *cname) {
           nscope = new_node("namespace");
           Setattr(nscope,"symtab", gscope);;
           nscope_inner = nscope;
    +      Delete(last);
           return base;
         }
         /* Try to locate the scope */
    @@ -924,7 +991,7 @@ static String *resolve_create_node_scope(String *cname) {
     	String *nname = Swig_symbol_qualifiedscopename(nstab);
     	if (tname && (Strcmp(tname,nname) == 0)) {
     	  ns = 0;
    -	  cname = base;
    +	  cname = Copy(last);
     	}
     	Delete(tname);
     	Delete(nname);
    @@ -932,19 +999,10 @@ static String *resolve_create_node_scope(String *cname) {
           if (ns) {
     	/* we will try to create a new node using the namespaces we
     	   can find in the scope name */
    -	List *scopes;
    +	List *scopes = Swig_scopename_tolist(prefix);
     	String *sname;
     	Iterator si;
    -	String *name = NewString(prefix);
    -	scopes = NewList();
    -	while (name) {
    -	  String *base = Swig_scopename_last(name);
    -	  String *tprefix = Swig_scopename_prefix(name);
    -	  Insert(scopes,0,base);
    -	  Delete(base);
    -	  Delete(name);
    -	  name = tprefix;
    -	}
    +
     	for (si = First(scopes); si.item; si = Next(si)) {
     	  Node *ns1,*ns2;
     	  sname = si.item;
    @@ -990,12 +1048,13 @@ static String *resolve_create_node_scope(String *cname) {
     	  nscope_inner = ns2;
     	  if (!nscope) nscope = ns2;
     	}
    -	cname = base;
    +	cname = Copy(last);
     	Delete(scopes);
           }
         }
         Delete(prefix);
       }
    +  Delete(last);
     
       return cname;
     }
    @@ -2631,9 +2690,8 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
     		  tscope = Swig_symbol_current();          /* Get the current scope */
     
     		  /* If the class name is qualified, we need to create or lookup namespace entries */
    -		  if (!inclass) {
    -		    $5 = resolve_create_node_scope($5);
    -		  }
    +		  $5 = resolve_create_node_scope($5, 0);
    +
     		  if (nscope_inner && Strcmp(nodeType(nscope_inner), "class") == 0) {
     		    outer_class	= nscope_inner;
     		  }
    @@ -3520,7 +3578,7 @@ cpp_class_decl  : storage_class cpptype idcolon inherit LBRACE {
     		   Setattr($$,"prev_symtab",Swig_symbol_current());
     		  
     		   /* If the class name is qualified.  We need to create or lookup namespace/scope entries */
    -		   scope = resolve_create_node_scope($3);
    +		   scope = resolve_create_node_scope($3, 1);
     		   /* save nscope_inner to the class - it may be overwritten in nested classes*/
     		   Setattr($$, "nested:innerscope", nscope_inner);
     		   Setattr($$, "nested:nscope", nscope);
    diff --git a/Source/Swig/misc.c b/Source/Swig/misc.c
    index cfa0c68b3..f80fb678f 100644
    --- a/Source/Swig/misc.c
    +++ b/Source/Swig/misc.c
    @@ -823,10 +823,11 @@ String *Swig_string_emangle(String *s) {
     
     
     /* -----------------------------------------------------------------------------
    - * Swig_scopename_prefix()
    + * Swig_scopename_split()
      *
    - * Take a qualified name like "A::B::C" and return the scope name.
    - * In this case, "A::B".   Returns NULL if there is no base.
    + * Take a qualified name like "A::B::C" and splits off the last name.
    + * In this case, returns "C" as last and "A::B" as prefix.
    + * Always returns non NULL for last, but prefix may be NULL if there is no prefix.
      * ----------------------------------------------------------------------------- */
     
     void Swig_scopename_split(const String *s, String **rprefix, String **rlast) {
    @@ -882,6 +883,12 @@ void Swig_scopename_split(const String *s, String **rprefix, String **rlast) {
       }
     }
     
    +/* -----------------------------------------------------------------------------
    + * Swig_scopename_prefix()
    + *
    + * Take a qualified name like "A::B::C" and return the scope name.
    + * In this case, "A::B".   Returns NULL if there is no base.
    + * ----------------------------------------------------------------------------- */
     
     String *Swig_scopename_prefix(const String *s) {
       char *tmp = Char(s);
    @@ -1067,6 +1074,31 @@ String *Swig_scopename_suffix(const String *s) {
       }
     }
     
    +/* -----------------------------------------------------------------------------
    + * Swig_scopename_tolist()
    + *
    + * Take a qualified scope name like "A::B::C" and convert it to a list.
    + * In this case, return a list of 3 elements "A", "B", "C".
    + * Returns an empty list if the input is empty.
    + * ----------------------------------------------------------------------------- */
    +
    +List *Swig_scopename_tolist(const String *s) {
    +  List *scopes = NewList();
    +  String *name = Len(s) == 0 ? 0 : NewString(s);
    +
    +  while (name) {
    +    String *last = 0;
    +    String *prefix = 0;
    +    Swig_scopename_split(name, &prefix, &last);
    +    Insert(scopes, 0, last);
    +    Delete(last);
    +    Delete(name);
    +    name = prefix;
    +  }
    +  Delete(name);
    +  return scopes;
    +}
    +
     /* -----------------------------------------------------------------------------
      * Swig_scopename_check()
      *
    diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h
    index f25f0993e..0bcd53a66 100644
    --- a/Source/Swig/swig.h
    +++ b/Source/Swig/swig.h
    @@ -326,6 +326,7 @@ extern int        ParmList_is_compactdefargs(ParmList *p);
       extern String *Swig_scopename_last(const String *s);
       extern String *Swig_scopename_first(const String *s);
       extern String *Swig_scopename_suffix(const String *s);
    +  extern List *Swig_scopename_tolist(const String *s);
       extern int Swig_scopename_check(const String *s);
       extern String *Swig_string_lower(String *s);
       extern String *Swig_string_upper(String *s);