mirror of https://github.com/swig/swig
%template scope enforcement and class definition fixes
The scoping rules around %template have been specified and enforced. 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 now 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 and explicit instantiations of std::vector are shown below: // valid namespace std { %template(vin) vector<int>; template class vector<int>; } // valid using namespace std; %template(vin) vector<int>; template class vector<int>; // valid using std::vector; %template(vin) vector<int>; template class vector<int>; // ill-formed namespace unrelated { using std::vector; %template(vin) vector<int>; template class vector<int>; } // ill-formed namespace unrelated { using namespace std; %template(vin) vector<int>; template class vector<int>; } // ill-formed namespace unrelated { namespace std { %template(vin) vector<int>; template class vector<int>; } } // ill-formed namespace unrelated { %template(vin) std::vector<int>; template class std::vector<int>; } When the scope is incorrect, an error now occurs such as: cpp_template_scope.i:34: Error: 'vector' resolves to 'std::vector' and was incorrectly instantiated in scope 'unrelated' instead of within scope 'std'. Previously SWIG accepted the ill-formed examples above but this led to numerous subtle template scope problems especially in the presence of using declarations and using directives as well as with %feature and %typemap. Actually, 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 std::vector; template class vector<int>; Similar fixes for defining classes using forward class references have also been put in place. For example: namespace Space1 { struct A; } namespace Space2 { struct Space1::A { void x(); } } will now error out with: cpp_class_definition.i:5: Error: 'Space1::A' resolves to 'Space1::A' and was incorrectly instantiated in scope 'Space2' instead of within scope 'Space1'.
This commit is contained in:
parent
97ae9d66bc
commit
959e627208
|
@ -253,6 +253,7 @@
|
|||
<li><a href="SWIGPlus.html#SWIGPlus_template_class_inheritance">Template base classes</a>
|
||||
<li><a href="SWIGPlus.html#SWIGPlus_template_specialization">Template specialization</a>
|
||||
<li><a href="SWIGPlus.html#SWIGPlus_template_member">Member templates</a>
|
||||
<li><a href="SWIGPlus.html#SWIGPlus_template_scoping">Scoping and templates</a>
|
||||
<li><a href="SWIGPlus.html#SWIGPlus_template_more">More on templates</a>
|
||||
</ul>
|
||||
<li><a href="SWIGPlus.html#SWIGPlus_namespaces">Namespaces</a>
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
<li><a href="#SWIGPlus_template_class_inheritance">Template base classes</a>
|
||||
<li><a href="#SWIGPlus_template_specialization">Template specialization</a>
|
||||
<li><a href="#SWIGPlus_template_member">Member templates</a>
|
||||
<li><a href="#SWIGPlus_template_scoping">Scoping and templates</a>
|
||||
<li><a href="#SWIGPlus_template_more">More on templates</a>
|
||||
</ul>
|
||||
<li><a href="#SWIGPlus_namespaces">Namespaces</a>
|
||||
|
@ -3599,7 +3600,108 @@ constructor, that will dispatch the proper call depending on the argument
|
|||
type.
|
||||
</p>
|
||||
|
||||
<H3><a name="SWIGPlus_template_more">6.18.7 More on templates</a></H3>
|
||||
<H3><a name="SWIGPlus_template_scoping">6.18.7 Scoping and templates</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The <tt>%template</tt> directive for a class template is the equivalent to an explicit instantiation
|
||||
of a C++ class template. The scope for a valid <tt>%template</tt> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, a few <tt>%template</tt> instantiations and C++ explicit instantiations are shown below:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
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>;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
When the scope is incorrect, such as for the ill-formed examples above, an error occurs:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
cpp_template_scope.i:34: Error: 'C' resolves to 'N::C' and was incorrectly instantiated
|
||||
in scope 'unrelated' instead of within scope 'N'.
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
// valid C++03, ill-formed C++11
|
||||
using N::C;
|
||||
template class C<int>;
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<b>Compatibility Note</b>: Versions prior to SWIG-4.0.0 did not error out with incorrectly scoped
|
||||
<tt>%template</tt> declarations, but this led to numerous subtle template scope problems.
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="SWIGPlus_template_more">6.18.8 More on templates</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -4348,9 +4450,9 @@ In the example below, the generic template type is used to rename to <tt>bbb</tt
|
|||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%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 {};
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
}
|
||||
|
||||
%}
|
||||
|
|
@ -136,6 +136,7 @@ CPP_TEST_CASES += \
|
|||
char_binary \
|
||||
char_strings \
|
||||
chartest \
|
||||
class_scope_namespace \
|
||||
class_forward \
|
||||
class_ignore \
|
||||
class_scope_weird \
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
|
@ -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'.
|
|
@ -0,0 +1,40 @@
|
|||
%module namespace_template
|
||||
|
||||
namespace test {
|
||||
template<typename T> T max(T a, T b) { return (a > b) ? a : b; }
|
||||
template<typename T> class vector {
|
||||
public:
|
||||
vector() { }
|
||||
~vector() { }
|
||||
};
|
||||
}
|
||||
|
||||
namespace test2 {
|
||||
using namespace test;
|
||||
%template(maxshort) max<short>;
|
||||
%template(vectorshort) vector<short>;
|
||||
}
|
||||
|
||||
namespace test3 {
|
||||
using test::max;
|
||||
using test::vector;
|
||||
%template(maxlong) max<long>;
|
||||
%template(vectorlong) vector<long>;
|
||||
}
|
||||
|
||||
namespace test4 {
|
||||
using namespace test;
|
||||
typedef int Integer;
|
||||
}
|
||||
|
||||
namespace test4 {
|
||||
%template(maxInteger) max<Integer>;
|
||||
%template(vectorInteger) vector<Integer>;
|
||||
}
|
||||
|
||||
using namespace test;
|
||||
namespace test5 {
|
||||
%template(maxdouble) max<double>;
|
||||
%template(vectordouble) vector<double>;
|
||||
}
|
||||
|
|
@ -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'.
|
|
@ -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().
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
%module xxx
|
||||
|
||||
namespace std {
|
||||
template<typename T> class vector {};
|
||||
}
|
||||
|
||||
struct S1 {};
|
||||
struct S2 {};
|
||||
struct S3 {};
|
||||
struct S4 {};
|
||||
struct S5 {};
|
||||
struct S6 {};
|
||||
struct S7 {};
|
||||
|
||||
// valid
|
||||
namespace std {
|
||||
%template(vi1) vector<S1>;
|
||||
template class vector<S1>;
|
||||
}
|
||||
|
||||
// valid
|
||||
using namespace std;
|
||||
%template(vi2) vector<S2>;
|
||||
template class vector<S2>;
|
||||
|
||||
// valid
|
||||
using std::vector;
|
||||
%template(vi3) vector<S3>;
|
||||
template class vector<S3>;
|
||||
|
||||
// ill-formed
|
||||
namespace unrelated {
|
||||
using std::vector;
|
||||
%template(vi4) vector<S4>;
|
||||
template class vector<S4>;
|
||||
}
|
||||
|
||||
// ill-formed
|
||||
namespace unrelated {
|
||||
using namespace std;
|
||||
%template(vi5) vector<S5>;
|
||||
template class vector<S5>;
|
||||
}
|
||||
|
||||
// ill-formed
|
||||
namespace unrelated {
|
||||
namespace std {
|
||||
%template(vi6) vector<S6>;
|
||||
template class vector<S6>;
|
||||
}
|
||||
}
|
||||
|
||||
// ill-formed
|
||||
namespace unrelated {
|
||||
%template(vi7) std::vector<S7>;
|
||||
template class std::vector<S7>;
|
||||
}
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
%module namespace_template
|
||||
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) vector<int>; /* Ruby, wrong class name */
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test2::vector<short>; /* Ruby, wrong class name */
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test3::vector<long>; /* Ruby, wrong class name */
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) vector<test4::Integer>; /* Ruby, wrong class name */
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector<int>; /* Ruby, wrong class name */
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector<short>; /* Ruby, wrong class name */
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector<long>; /* Ruby, wrong class name */
|
||||
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) test::vector<test::Char>; /* Ruby, wrong class name */
|
||||
|
||||
%{
|
||||
#ifdef max
|
||||
|
@ -23,20 +23,9 @@ namespace test {
|
|||
char * blah(T x) {
|
||||
return (char *) "vector::blah";
|
||||
}
|
||||
void vectoruse(vector<T> a, test::vector<T> 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<T> a, test::vector<T> b) {}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -55,30 +45,26 @@ using namespace test;
|
|||
%template(maxint) max<int>;
|
||||
%template(vectorint) vector<int>;
|
||||
|
||||
namespace test2 {
|
||||
using namespace test;
|
||||
namespace test {
|
||||
%template(maxshort) max<short>;
|
||||
%template(vectorshort) vector<short>;
|
||||
}
|
||||
|
||||
namespace test3 {
|
||||
using test::max;
|
||||
using test::vector;
|
||||
namespace test {
|
||||
%template(maxlong) max<long>;
|
||||
%template(vectorlong) vector<long>;
|
||||
}
|
||||
|
||||
%inline %{
|
||||
|
||||
namespace test4 {
|
||||
using namespace test;
|
||||
typedef int Integer;
|
||||
namespace test {
|
||||
typedef char Char;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
namespace test4 {
|
||||
%template(maxInteger) max<Integer>;
|
||||
%template(vectorInteger) vector<Integer>;
|
||||
namespace test {
|
||||
%template(maxchar) max<Char>;
|
||||
%template(vectorchar) vector<Char>;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,6 @@ namespace one
|
|||
};
|
||||
}
|
||||
|
||||
%define PTR_DEF(o)
|
||||
typedef one::Ptr<o> o ## _ptr;
|
||||
%template(o ## _ptr) one::Ptr<o>;
|
||||
%enddef
|
||||
|
||||
namespace one
|
||||
{
|
||||
class Obj1
|
||||
|
@ -63,7 +58,8 @@ namespace one
|
|||
void donothing() {}
|
||||
};
|
||||
|
||||
PTR_DEF(Obj1)
|
||||
typedef one::Ptr<Obj1> Obj1_ptr;
|
||||
%template(Obj1_ptr) one::Ptr<Obj1>;
|
||||
}
|
||||
|
||||
namespace two
|
||||
|
@ -75,6 +71,9 @@ namespace two
|
|||
void donothing() {}
|
||||
};
|
||||
|
||||
PTR_DEF(Obj2)
|
||||
typedef one::Ptr<Obj2> Obj2_ptr;
|
||||
}
|
||||
|
||||
using two::Obj2;
|
||||
%template(Obj2_ptr) one::Ptr<Obj2>;
|
||||
|
||||
|
|
|
@ -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 <typename T> struct Typemap {
|
||||
%typemap(in) T {
|
||||
$1 = -99;
|
||||
}
|
||||
};
|
||||
template <> struct Typemap<short> { // 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 <typename T> struct Breeze {
|
||||
template <typename TMT> struct Typemap {
|
||||
#ifdef SWIG
|
||||
%typemap(in) TMT {
|
||||
$1 = -99;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
template <typename TMT> struct TypemapShort {
|
||||
#ifdef SWIG
|
||||
%typemap(in) short {
|
||||
$1 = -77;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int methodInt1(int s) { return s; }
|
||||
#if defined(SWIG)
|
||||
%template() Typemap<int>;
|
||||
|
@ -29,7 +34,7 @@ template <typename T> struct Breeze {
|
|||
|
||||
short methodShort1(short s) { return s; }
|
||||
#if defined(SWIG)
|
||||
%template(TypemapShort) Typemap<short>; // should issue warning SWIGWARN_PARSE_NESTED_TEMPLATE
|
||||
%template() TypemapShort<short>;
|
||||
#endif
|
||||
short methodShort2(short s) { return s; } // should pick up the typemap within Typemap<short>
|
||||
};
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace One {
|
|||
%template(H) One::OneParm<int **>;
|
||||
|
||||
// %template scope explicit specializations
|
||||
namespace ONE {
|
||||
namespace One {
|
||||
%template(I) One::OneParm<float>;
|
||||
%template(J) ::One::OneParm<float *>;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace One {
|
|||
}
|
||||
|
||||
// %template scope partial specializations
|
||||
namespace ONE {
|
||||
namespace One {
|
||||
%template(BB) One::OneParm<bool *>;
|
||||
%template(BBB) ::One::OneParm<char *>;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace One {
|
|||
%template(H) One::OneParm<TypeDef::IntPtrPtr>;
|
||||
|
||||
// %template scope explicit specializations
|
||||
namespace ONE {
|
||||
namespace One {
|
||||
%template(I) One::OneParm<TypeDef::Float>;
|
||||
%template(J) ::One::OneParm<TypeDef::FloatPtr>;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ namespace One {
|
|||
}
|
||||
|
||||
// %template scope partial specializations
|
||||
namespace ONE {
|
||||
namespace One {
|
||||
%template(BB) One::OneParm<TypeDef::BoolPtr>;
|
||||
%template(BBB) ::One::OneParm<TypeDef::CharPtr>;
|
||||
}
|
||||
|
|
|
@ -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($<node>$,"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($<node>$, "nested:innerscope", nscope_inner);
|
||||
Setattr($<node>$, "nested:nscope", nscope);
|
||||
|
|
|
@ -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()
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue