Fix infinite loop handling non-type template parameters

Fixes infinite loop due to () brackets in a non-type template
parameter containing an expression

Fixes #2418

Non-trivial expressions are still not qualified properly though.
This commit is contained in:
William S Fulton 2022-11-02 19:57:02 +00:00
commit 52edda64c1
6 changed files with 69 additions and 3 deletions

View file

@ -50,3 +50,9 @@ Version 4.2.0 (in progress)
shown into the user interface file will provide the appropriate fix and 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 the warning will disappear. This is important to do as swig-4.2 will
not be able to provide this helpful warning. 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.

View file

@ -639,6 +639,7 @@ CPP11_TEST_BROKEN = \
# C++14 test cases. # C++14 test cases.
CPP14_TEST_CASES += \ CPP14_TEST_CASES += \
cpp14_binary_integer_literals \ cpp14_binary_integer_literals \
cpp14_enable_if_t \
# Broken C++14 test cases. # Broken C++14 test cases.
CPP14_TEST_BROKEN = \ CPP14_TEST_BROKEN = \

View file

@ -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 <type_traits>
typedef int node_t;
typedef int position_t;
template <typename A, typename B, std::enable_if_t<std::is_integral_v<A>, 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 <typename A, typename B, std::enable_if_t<(std::is_integral_v<A>), bool> = true>
void enableif2(const A a, const B b) {}
template <typename A, typename B, std::enable_if_t<(std::is_integral_v<A> || std::is_same_v<A, node_t>), bool> = true>
void enableif3(const A a, const B b) {}
template <typename A, typename B, std::enable_if_t<(std::is_integral_v<A> or std::is_same_v<A, node_t>) and (std::is_integral_v<B> or std::is_same_v<B, position_t>), bool> = true>
void enableif4(const A a, const B b) {}
template <typename A, typename B, std::enable_if_t<(std::is_integral_v<A> and std::is_integral_v<B>), bool> = true>
int enableif5(const A a, const B b) {
return a + b;
}
void tester() {
enableif5<int, int>(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<int, int, true>; // workaround

View file

@ -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");
}
}

View file

@ -1518,7 +1518,8 @@ Node *Swig_symbol_isoverloaded(Node *n) {
static SwigType *symbol_template_qualify(const SwigType *e, Symtab *st) { static SwigType *symbol_template_qualify(const SwigType *e, Symtab *st) {
String *tprefix, *tsuffix; String *tprefix, *tsuffix;
SwigType *qprefix; SwigType *qprefix;
List *targs; String *targs;
List *targslist;
Node *tempn; Node *tempn;
Symtab *tscope; Symtab *tscope;
Iterator ti; Iterator ti;
@ -1541,12 +1542,15 @@ static SwigType *symbol_template_qualify(const SwigType *e, Symtab *st) {
tprefix = SwigType_templateprefix(e); tprefix = SwigType_templateprefix(e);
tsuffix = SwigType_templatesuffix(e); tsuffix = SwigType_templatesuffix(e);
qprefix = Swig_symbol_type_qualify(tprefix, st); 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); tempn = Swig_symbol_clookup_local(tprefix, st);
tscope = tempn ? Getattr(tempn, "sym:symtab") : 0; tscope = tempn ? Getattr(tempn, "sym:symtab") : 0;
Append(qprefix, "<("); Append(qprefix, "<(");
for (ti = First(targs); ti.item;) { for (ti = First(targslist); ti.item;) {
String *vparm; 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); String *qparm = Swig_symbol_type_qualify(ti.item, st);
if (tscope && (tscope != st)) { if (tscope && (tscope != st)) {
String *ty = Swig_symbol_type_qualify(qparm, tscope); 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(tprefix);
Delete(tsuffix); Delete(tsuffix);
Delete(targs); Delete(targs);
Delete(targslist);
#ifdef SWIG_DEBUG #ifdef SWIG_DEBUG
Printf(stderr, "symbol_temp_qual %s %s\n", e, qprefix); Printf(stderr, "symbol_temp_qual %s %s\n", e, qprefix);
#endif #endif

View file

@ -1148,6 +1148,7 @@ SwigType *SwigType_typedef_qualified(const SwigType *t) {
Append(qprefix, "<("); Append(qprefix, "<(");
pi = First(parms); pi = First(parms);
while ((p = pi.item)) { 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); String *qt = SwigType_typedef_qualified(p);
if (Equal(qt, p)) { /* && (!Swig_scopename_check(qt))) */ if (Equal(qt, p)) { /* && (!Swig_scopename_check(qt))) */
/* No change in value. It is entirely possible that the parameter is an integer value. /* No change in value. It is entirely possible that the parameter is an integer value.