diff --git a/CHANGES.current b/CHANGES.current index bbfa22839..500ab4044 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -50,3 +50,9 @@ Version 4.2.0 (in progress) shown into the user interface file will provide the appropriate fix and the warning will disappear. This is important to do as swig-4.2 will not be able to provide this helpful warning. + +2022-11-02: wsfulton + #2418 Fix infinite loop handling non-type template parameters. + + Fixes infinite loop due to () brackets in a non-type template + parameter containing an expression. diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 4681571e2..c52a74dd3 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -639,6 +639,7 @@ CPP11_TEST_BROKEN = \ # C++14 test cases. CPP14_TEST_CASES += \ cpp14_binary_integer_literals \ + cpp14_enable_if_t \ # Broken C++14 test cases. CPP14_TEST_BROKEN = \ diff --git a/Examples/test-suite/cpp14_enable_if_t.i b/Examples/test-suite/cpp14_enable_if_t.i new file mode 100644 index 000000000..a2e483380 --- /dev/null +++ b/Examples/test-suite/cpp14_enable_if_t.i @@ -0,0 +1,34 @@ +%module cpp14_enable_if_t + +// test use of enable_if_t but without full %template instantiation, that is no enable_if_t definition is parsed + +%inline %{ +#include +typedef int node_t; +typedef int position_t; + +template , bool> = true> + void enableif1(const A a, const B b) {} + +// tests non-type template parameters within () brackets - was causing an infinite loop, issue #2418 +template ), bool> = true> + void enableif2(const A a, const B b) {} + +template || std::is_same_v), bool> = true> + void enableif3(const A a, const B b) {} + +template or std::is_same_v) and (std::is_integral_v or std::is_same_v), bool> = true> + void enableif4(const A a, const B b) {} + +template and std::is_integral_v), bool> = true> + int enableif5(const A a, const B b) { + return a + b; + } + +void tester() { + enableif5(10, 20); +} +%} + +// non-type template parameters working well in SWIG, below is a simple workaround as the 3rd parameter is defaulted for enable_if_t (which is just SFINAE to give a nice C++ compiler error) +%template(enableif5) enableif5; // workaround diff --git a/Examples/test-suite/java/cpp14_enable_if_t_runme.java b/Examples/test-suite/java/cpp14_enable_if_t_runme.java new file mode 100644 index 000000000..ade061be3 --- /dev/null +++ b/Examples/test-suite/java/cpp14_enable_if_t_runme.java @@ -0,0 +1,19 @@ +import cpp14_enable_if_t.*; + +public class cpp14_enable_if_t_runme { + + static { + try { + System.loadLibrary("cpp14_enable_if_t"); + } 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[]) + { + if (cpp14_enable_if_t.enableif5(10, 20) != 30) + throw new RuntimeException("enableif5 not working"); + } +} diff --git a/Source/Swig/symbol.c b/Source/Swig/symbol.c index d39696f5b..107b1caef 100644 --- a/Source/Swig/symbol.c +++ b/Source/Swig/symbol.c @@ -1518,7 +1518,8 @@ Node *Swig_symbol_isoverloaded(Node *n) { static SwigType *symbol_template_qualify(const SwigType *e, Symtab *st) { String *tprefix, *tsuffix; SwigType *qprefix; - List *targs; + String *targs; + List *targslist; Node *tempn; Symtab *tscope; Iterator ti; @@ -1541,12 +1542,15 @@ static SwigType *symbol_template_qualify(const SwigType *e, Symtab *st) { tprefix = SwigType_templateprefix(e); tsuffix = SwigType_templatesuffix(e); qprefix = Swig_symbol_type_qualify(tprefix, st); - targs = SwigType_parmlist(e); + targs = SwigType_templateargs(e); + targslist = SwigType_parmlist(targs); tempn = Swig_symbol_clookup_local(tprefix, st); tscope = tempn ? Getattr(tempn, "sym:symtab") : 0; Append(qprefix, "<("); - for (ti = First(targs); ti.item;) { + for (ti = First(targslist); ti.item;) { String *vparm; + /* TODO: the logic here should be synchronised with that in SwigType_typedef_qualified() */ + /* TODO: ti.item might be a non-type parameter possibly within (), eg: (std::is_integral_v<(A)>||std::is_same_v<(A,node_t)>) */ String *qparm = Swig_symbol_type_qualify(ti.item, st); if (tscope && (tscope != st)) { String *ty = Swig_symbol_type_qualify(qparm, tscope); @@ -1568,6 +1572,7 @@ static SwigType *symbol_template_qualify(const SwigType *e, Symtab *st) { Delete(tprefix); Delete(tsuffix); Delete(targs); + Delete(targslist); #ifdef SWIG_DEBUG Printf(stderr, "symbol_temp_qual %s %s\n", e, qprefix); #endif diff --git a/Source/Swig/typesys.c b/Source/Swig/typesys.c index 74384f860..4a11790c7 100644 --- a/Source/Swig/typesys.c +++ b/Source/Swig/typesys.c @@ -1148,6 +1148,7 @@ SwigType *SwigType_typedef_qualified(const SwigType *t) { Append(qprefix, "<("); pi = First(parms); while ((p = pi.item)) { + /* TODO: the logic here should be synchronised with that in symbol_template_qualify() in symbol.c */ String *qt = SwigType_typedef_qualified(p); if (Equal(qt, p)) { /* && (!Swig_scopename_check(qt))) */ /* No change in value. It is entirely possible that the parameter is an integer value.