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 @@
+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. +
+ + +@@ -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);