diff --git a/Doc/Manual/Warnings.html b/Doc/Manual/Warnings.html
index 58350ea63..879d5ffb7 100644
--- a/Doc/Manual/Warnings.html
+++ b/Doc/Manual/Warnings.html
@@ -415,6 +415,7 @@ example.i(4) : Syntax error in input(1).
327. Extern template ignored.
328. Value assigned to name not used due to limited parsing implementation.
329. Using declaration 'name' for inheriting constructors uses base 'name' which is not an immediate base of 'name'.
+330. Template forward class instantiation 'templ' with name 'name' is ineffective.
340. Lambda expressions and closures are not fully supported yet.
344. Unable to deduce decltype for 'expr'.
345. Unable to deduce auto return type for 'name' (ignored).
diff --git a/Examples/test-suite/errors/cpp_invalid_template.i b/Examples/test-suite/errors/cpp_invalid_template.i
index 45ad73908..dfeca133f 100644
--- a/Examples/test-suite/errors/cpp_invalid_template.i
+++ b/Examples/test-suite/errors/cpp_invalid_template.i
@@ -7,3 +7,8 @@ namespace UUU {
}
%template(xxx) UUU::JJJ;
+
+%template(TTT_int) VVV::TTT; // needs to be after template is parsed
+namespace VVV {
+ template struct TTT {};
+}
diff --git a/Examples/test-suite/errors/cpp_invalid_template.stderr b/Examples/test-suite/errors/cpp_invalid_template.stderr
index f39464942..08119043d 100644
--- a/Examples/test-suite/errors/cpp_invalid_template.stderr
+++ b/Examples/test-suite/errors/cpp_invalid_template.stderr
@@ -1,2 +1,3 @@
cpp_invalid_template.i:3: Error: Template 'SSS::AAA' undefined.
cpp_invalid_template.i:9: Error: 'JJJ' is not defined as a template. (classforward)
+cpp_invalid_template.i:11: Error: Template 'VVV::TTT' undefined.
diff --git a/Examples/test-suite/errors/cpp_template_forward.i b/Examples/test-suite/errors/cpp_template_forward.i
new file mode 100644
index 000000000..5b5e3f198
--- /dev/null
+++ b/Examples/test-suite/errors/cpp_template_forward.i
@@ -0,0 +1,20 @@
+%module xxx
+
+
+namespace Space {
+ template struct ForwardDeclaredTemplate;
+ %template(ForwardDeclaredTemplate_double) ForwardDeclaredTemplate;
+
+ template struct ForwardDeclaredSpecialized;
+ %template(ForwardDeclaredTemplate_int) ForwardDeclaredSpecialized; // no primary defined
+ %template(ForwardDeclaredTemplate_double) ForwardDeclaredSpecialized; // needs to be after the specialized template definition.
+ template <> struct ForwardDeclaredSpecialized {
+ void specialized(const ForwardDeclaredSpecialized& other) { }
+ };
+
+ template struct ForwardDeclaredMisplacedPrimary;
+ %template(ForwardDeclaredTemplate_double) ForwardDeclaredMisplacedPrimary; // needs to be after the primary template definition.
+ template struct ForwardDeclaredMisplacedPrimary {
+ void primary(const ForwardDeclaredMisplacedPrimary& other) { }
+ };
+}
diff --git a/Examples/test-suite/errors/cpp_template_forward.stderr b/Examples/test-suite/errors/cpp_template_forward.stderr
new file mode 100644
index 000000000..5919d5ea3
--- /dev/null
+++ b/Examples/test-suite/errors/cpp_template_forward.stderr
@@ -0,0 +1,4 @@
+cpp_template_forward.i:6: Warning 330: Template instantiation of forward class declaration 'Space::ForwardDeclaredTemplate< double >' with name 'ForwardDeclaredTemplate_double' is ineffective.
+cpp_template_forward.i:9: Warning 330: Template instantiation of forward class declaration 'Space::ForwardDeclaredSpecialized< int >' with name 'ForwardDeclaredTemplate_int' is ineffective.
+cpp_template_forward.i:10: Warning 330: Template instantiation of forward class declaration 'Space::ForwardDeclaredSpecialized< double >' with name 'ForwardDeclaredTemplate_double' is ineffective.
+cpp_template_forward.i:16: Warning 330: Template instantiation of forward class declaration 'Space::ForwardDeclaredMisplacedPrimary< double >' with name 'ForwardDeclaredTemplate_double' is ineffective.
diff --git a/Examples/test-suite/template_specialization.i b/Examples/test-suite/template_specialization.i
index b79fee4dd..a6050a192 100644
--- a/Examples/test-suite/template_specialization.i
+++ b/Examples/test-suite/template_specialization.i
@@ -3,6 +3,8 @@
%rename(not1) *::operator!() const;
%rename(negate) *::operator-() const;
+%warnfilter(SWIGWARN_PARSE_TEMPLATE_FORWARD) vfncs::OnlySpecialized;
+
%inline %{
namespace vfncs {
@@ -45,7 +47,7 @@ namespace vfncs {
%template(OnlySpecialized_int) OnlySpecialized;
// Primary instantiation with only primary template forward declaration
- %template(OnlySpecialized_double) OnlySpecialized; // silently ignored - probably should warn
+ %template(OnlySpecialized_double) OnlySpecialized; // ignored with a warning
}
%{
diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
index c1e3faa36..9a8e3e3e3 100644
--- a/Source/CParse/parser.y
+++ b/Source/CParse/parser.y
@@ -2905,7 +2905,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
if (GetFlag(nn, "instantiate")) {
Delattr(nn, "instantiate");
{
- int nnisclass = (Strcmp(Getattr(nn, "templatetype"), "class") == 0); /* if not a class template it is a function template */
+ int nnisclass = (Strcmp(Getattr(nn, "templatetype"), "class") == 0); /* class template not a classforward nor function template */
Parm *tparms = Getattr(nn, "templateparms");
int specialized = !tparms; /* fully specialized (an explicit specialization) */
String *tname = Copy(idcolonnt);
@@ -2960,6 +2960,13 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
}
add_symbols_copy(templnode);
+ if (Equal(nodeType(templnode), "classforward")) {
+ SWIG_WARN_NODE_BEGIN(templnode);
+ /* A full template class definition is required in order to wrap a template class as a proxy class so this %template is ineffective. */
+ Swig_warning(WARN_PARSE_TEMPLATE_FORWARD, cparse_file, cparse_line, "Template forward class instantiation '%s' with name '%s' is ineffective.\n", Swig_name_decl(templnode), Getattr(templnode, "sym:name"));
+ SWIG_WARN_NODE_END(templnode);
+ }
+
if (Strcmp(nodeType(templnode),"class") == 0) {
/* Identify pure abstract methods */
diff --git a/Source/CParse/templ.c b/Source/CParse/templ.c
index 4289e5c70..253797b7f 100644
--- a/Source/CParse/templ.c
+++ b/Source/CParse/templ.c
@@ -223,6 +223,8 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
cn = nextSibling(cn);
}
}
+ } else if (Equal(nodeType, "classforward")) {
+ /* Nothing to expand */
} else if (Equal(nodeType, "constructor")) {
if (!(Getattr(n, "templatetype"))) {
String *symname = Getattr(n, "sym:name");
@@ -1172,12 +1174,10 @@ Node *Swig_cparse_template_locate(String *name, Parm *instantiated_parms, String
if (n) {
String *nodeType = nodeType(n);
- int isclass = 0;
assert(Equal(nodeType, "template"));
- (void)nodeType;
- isclass = (Equal(Getattr(n, "templatetype"), "class"));
+ String *templatetype = Getattr(n, "templatetype");
- if (isclass) {
+ if (Equal(templatetype, "class") || Equal(templatetype, "classforward")) {
Node *primary = Getattr(n, "primarytemplate");
Parm *tparmsfound = Getattr(primary ? primary : n, "templateparms");
int specialized = !tparmsfound; /* fully specialized (an explicit specialization) */
@@ -1361,8 +1361,8 @@ static void expand_defaults(ParmList *expanded_templateparms) {
ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *primary, Node *templ) {
ParmList *expanded_templateparms = CopyParmList(instantiated_parms);
-
String *templatetype = Getattr(primary, "templatetype");
+
if (Equal(templatetype, "class") || Equal(templatetype, "classforward")) {
/* Class template */
ParmList *templateparms = Getattr(primary, "templateparms");
@@ -1400,8 +1400,9 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *
ParmList *Swig_cparse_template_partialargs_expand(ParmList *partially_specialized_parms, Node *primary, ParmList *templateparms) {
ParmList *expanded_templateparms = CopyParmList(partially_specialized_parms);
+ String *templatetype = Getattr(primary, "templatetype");
- if (Equal(Getattr(primary, "templatetype"), "class")) {
+ if (Equal(templatetype, "class") || Equal(templatetype, "classforward")) {
/* Class template */
int variadic = ParmList_variadic_parm(templateparms) ? 1 : 0;
/* Add default arguments from primary template */
diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h
index 6e0c083e0..38dc75c45 100644
--- a/Source/Include/swigwarn.h
+++ b/Source/Include/swigwarn.h
@@ -96,6 +96,7 @@
#define WARN_PARSE_EXTERN_TEMPLATE 327
#define WARN_PARSE_ASSIGNED_VALUE 328
#define WARN_PARSE_USING_CONSTRUCTOR 329
+#define WARN_PARSE_TEMPLATE_FORWARD 330
#define WARN_CPP11_LAMBDA 340
/* Unused since 3.0.11: #define WARN_CPP11_ALIAS_DECLARATION 341 */