Support deducing type of some expressions
This change only supports expressions involving literals of built-in
types, and `int` expressions aren't supported (due to the parser
currently setting .type=T_INT when in situations where that isn't
or may not be the correct type).
diff --git a/CHANGES.current b/CHANGES.current
index 6ff0868..c770089 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -8,6 +8,12 @@
===========================
2023-05-25: olly
+ C++11 `auto` variables and `decltype()` can now deduce the
+ type of some expressions which involve literals of built-in types.
+ Currently int is not supported due to the parser misusing T_INT
+ for situations where the type isn't actually known.
+
+2023-05-25: olly
#1125 Support parsing C++11 auto variables. This uses the
existing type deduction code from decltype so has the same
limitations, and such variables will only actually be wrapped
diff --git a/Doc/Devel/scanner.html b/Doc/Devel/scanner.html
index 94807ff..cda102f 100644
--- a/Doc/Devel/scanner.html
+++ b/Doc/Devel/scanner.html
@@ -242,6 +242,7 @@
SWIG_TOKEN_ID identifier
SWIG_TOKEN_FLOAT Floating point with F suffix (e.g., 3.1415F)
SWIG_TOKEN_DOUBLE Floating point (e.g., 3.1415 )
+SWIG_TOKEN_LONGDOUBLE Floating point with L suffix (e.g., 3.1415L)
SWIG_TOKEN_INT Integer (e.g., 314)
SWIG_TOKEN_UINT Unsigned integer (e.g., 314U)
SWIG_TOKEN_LONG Long integer (e.g., 314L)
diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html
index 06cc2fa..9aceb8d 100644
--- a/Doc/Manual/CPlusPlus11.html
+++ b/Doc/Manual/CPlusPlus11.html
@@ -721,8 +721,9 @@
<p><tt>decltype()</tt> is supported with limitations. SWIG can parse
-all uses, but can only deduce the type for single variables, <tt>true</tt> and
-<tt>false</tt>. For example, the following code will work:</p>
+all uses, but can only deduce the type for single variables, and for
+some expressions involving only literal values of built-in C++ types.
+For example, the following code will work:</p>
<div class="code"><pre>
int i;
decltype(i) j;
diff --git a/Examples/test-suite/cpp11_auto_variable.i b/Examples/test-suite/cpp11_auto_variable.i
index da05f57..67988b9 100644
--- a/Examples/test-suite/cpp11_auto_variable.i
+++ b/Examples/test-suite/cpp11_auto_variable.i
@@ -5,6 +5,21 @@
static auto t = true;
static constexpr auto f = false;
+static auto la = 1.0L;
+static auto da = 1.0;
+static auto fa = 1.0f;
+static constexpr auto lc = 1.0L;
+static constexpr auto dc = 1.0;
+static constexpr auto fc = 1.0f;
+
+static constexpr auto pi_approx = 355. / 133;
+
+static constexpr auto Bar = "foo";
+static constexpr auto Foo = "bar";
+
+static constexpr auto Bar2 = Bar;
+static constexpr auto Foo2 = Foo;
+
%}
// SWIG currently can't deduce the type for examples below:
@@ -12,12 +27,6 @@
%inline %{
-static auto Bar = "foo";
-static constexpr auto Foo = "bar";
-
-static auto Bar2 = Bar;
-static constexpr auto Foo2 = Foo;
-
static auto Bar3 = f ? Bar : Bar2;
static constexpr auto Foo3 = f ? Foo : Foo2;
diff --git a/Examples/test-suite/cpp11_template_parameters_decltype.i b/Examples/test-suite/cpp11_template_parameters_decltype.i
index 257d1ec..f61e489 100644
--- a/Examples/test-suite/cpp11_template_parameters_decltype.i
+++ b/Examples/test-suite/cpp11_template_parameters_decltype.i
@@ -4,6 +4,15 @@
%include <std_vector.i>
%include <std_pair.i>
+%inline %{
+// Github issue #1589
+template <decltype(true) X = true>
+void A() { }
+%}
+
+// %template(A) A<>; // not working
+%template(A) A<true>; // workaround
+
#pragma SWIG nowarn=SWIGWARN_CPP11_DECLTYPE
// Non-template expression equivalent to template expression further down:
@@ -34,13 +43,3 @@
// %template(Json) Json::Json<Converter>; // not working
%template(Json) Json::Json<Converter, std::string>; // workaround
-
-
-%inline %{
-// Github issue #1589
-template <decltype(true) X = true>
-void A() { }
-%}
-
-// %template(A) A<>; // not working
-%template(A) A<true>; // workaround
diff --git a/Examples/test-suite/php/cpp11_auto_variable_runme.php b/Examples/test-suite/php/cpp11_auto_variable_runme.php
index c8ddc56..5e831a8 100644
--- a/Examples/test-suite/php/cpp11_auto_variable_runme.php
+++ b/Examples/test-suite/php/cpp11_auto_variable_runme.php
@@ -5,7 +5,7 @@
// No new functions
check::functions(array());
check::classes(array('cpp11_auto_variable'));
-check::globals(array('f', 't'));
+check::globals(array('f', 't', 'la', 'da', 'fa', 'lc', 'dc', 'fc', 'pi_approx', 'Bar', 'Bar2', 'Foo', 'Foo2'));
check::equal(f_get(), false);
check::equal(t_get(), true);
@@ -14,3 +14,15 @@
check::equal(t_get(), false);
check::equal(function_exists('f_set'), false, "f should be constant but f_set() exists");
+
+check::equal(fa_get(), 1.0);
+check::equal(da_get(), 1.0);
+// PHP doesn't have a native "long double" type, so SWIG/PHP doesn't have
+// typemaps for it and so it should get wrapped as an opaque type.
+check::str_contains(la_get(), "SWIGPointer(");
+
+check::equal(fc_get(), 1.0);
+check::equal(dc_get(), 1.0);
+// PHP doesn't have a native "long double" type, so SWIG/PHP doesn't have
+// typemaps for it and so it should get wrapped as an opaque type.
+check::str_contains(lc_get(), "SWIGPointer(");
diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c
index 3395131..3d17db0 100644
--- a/Source/CParse/cscanner.c
+++ b/Source/CParse/cscanner.c
@@ -421,9 +421,14 @@
return NUM_ULONGLONG;
case SWIG_TOKEN_DOUBLE:
+ return NUM_DOUBLE;
+
case SWIG_TOKEN_FLOAT:
return NUM_FLOAT;
+ case SWIG_TOKEN_LONGDOUBLE:
+ return NUM_LONGDOUBLE;
+
case SWIG_TOKEN_BOOL:
return NUM_BOOL;
@@ -622,29 +627,35 @@
switch (l) {
case NUM_INT:
+ yylval.dtype.type = T_INT;
+ goto num_common;
+ case NUM_DOUBLE:
+ yylval.dtype.type = T_DOUBLE;
+ goto num_common;
case NUM_FLOAT:
+ yylval.dtype.type = T_FLOAT;
+ goto num_common;
+ case NUM_LONGDOUBLE:
+ yylval.dtype.type = T_LONGDOUBLE;
+ goto num_common;
case NUM_ULONG:
+ yylval.dtype.type = T_ULONG;
+ goto num_common;
case NUM_LONG:
+ yylval.dtype.type = T_LONG;
+ goto num_common;
case NUM_UNSIGNED:
+ yylval.dtype.type = T_UINT;
+ goto num_common;
case NUM_LONGLONG:
+ yylval.dtype.type = T_LONGLONG;
+ goto num_common;
case NUM_ULONGLONG:
+ yylval.dtype.type = T_ULONGLONG;
+ goto num_common;
case NUM_BOOL:
- if (l == NUM_INT)
- yylval.dtype.type = T_INT;
- if (l == NUM_FLOAT)
- yylval.dtype.type = T_DOUBLE;
- if (l == NUM_ULONG)
- yylval.dtype.type = T_ULONG;
- if (l == NUM_LONG)
- yylval.dtype.type = T_LONG;
- if (l == NUM_UNSIGNED)
- yylval.dtype.type = T_UINT;
- if (l == NUM_LONGLONG)
- yylval.dtype.type = T_LONGLONG;
- if (l == NUM_ULONGLONG)
- yylval.dtype.type = T_ULONGLONG;
- if (l == NUM_BOOL)
- yylval.dtype.type = T_BOOL;
+ yylval.dtype.type = T_BOOL;
+num_common:
yylval.dtype.val = NewString(Scanner_text(scan));
yylval.dtype.bitfield = 0;
yylval.dtype.throws = 0;
diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
index 96bf535..9074114 100644
--- a/Source/CParse/parser.y
+++ b/Source/CParse/parser.y
@@ -1652,7 +1652,7 @@
%token <id> STRING WSTRING
%token <loc> INCLUDE IMPORT INSERT
%token <str> CHARCONST WCHARCONST
-%token <dtype> NUM_INT NUM_FLOAT NUM_UNSIGNED NUM_LONG NUM_ULONG NUM_LONGLONG NUM_ULONGLONG NUM_BOOL
+%token <dtype> NUM_INT NUM_DOUBLE NUM_FLOAT NUM_LONGDOUBLE NUM_UNSIGNED NUM_LONG NUM_ULONG NUM_LONGLONG NUM_ULONGLONG NUM_BOOL
%token <intvalue> TYPEDEF
%token <type> TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_WCHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_COMPLEX TYPE_TYPEDEF TYPE_RAW TYPE_NON_ISO_INT8 TYPE_NON_ISO_INT16 TYPE_NON_ISO_INT32 TYPE_NON_ISO_INT64
%token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE PERIOD ELLIPSIS
@@ -1772,8 +1772,13 @@
Node *n = Swig_symbol_clookup(dtype->val, 0);
if (n) {
return Getattr(n, "type");
- } else if (Equal(dtype->val, "true") || Equal(dtype->val, "false")) {
- return NewString("bool");
+ } else if (dtype->type != T_AUTO && dtype->type != T_INT) {
+ /* Try to deduce the type from the T_* type code.
+ *
+ * Sadly we can't trust T_INT because several places in the parser set
+ * .type = T_INT when it may not be (or even definitely isn't).
+ */
+ return NewSwigType(dtype->type);
} else {
return NULL;
}
@@ -5350,7 +5355,7 @@
if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
$$.val = NewString(scanner_ccode);
$$.rawval = 0;
- $$.type = T_INT;
+ $$.type = T_INT; /* This may be a lie. */
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
@@ -5370,7 +5375,7 @@
| empty {
$$.val = 0;
$$.rawval = 0;
- $$.type = T_INT;
+ $$.type = T_INT; /* This is a lie. */
$$.bitfield = 0;
$$.throws = 0;
$$.throwf = 0;
@@ -6628,7 +6633,7 @@
| type {
Node *n;
$$.val = $1;
- $$.type = T_INT;
+ $$.type = T_INT; /* This may be a lie. */
/* Check if value is in scope */
n = Swig_symbol_clookup($1,0);
if (n) {
@@ -6835,7 +6840,9 @@
;
exprnum : NUM_INT { $$ = $1; }
+ | NUM_DOUBLE { $$ = $1; }
| NUM_FLOAT { $$ = $1; }
+ | NUM_LONGDOUBLE { $$ = $1; }
| NUM_UNSIGNED { $$ = $1; }
| NUM_LONG { $$ = $1; }
| NUM_ULONG { $$ = $1; }
diff --git a/Source/Preprocessor/expr.c b/Source/Preprocessor/expr.c
index 95e05cf..c13a75e 100644
--- a/Source/Preprocessor/expr.c
+++ b/Source/Preprocessor/expr.c
@@ -355,7 +355,7 @@
stack[sp].value = 0;
stack[sp].svalue = 0;
stack[sp].op = EXPR_VALUE;
- } else if ((token == SWIG_TOKEN_FLOAT) || (token == SWIG_TOKEN_DOUBLE)) {
+ } else if (token == SWIG_TOKEN_FLOAT || token == SWIG_TOKEN_DOUBLE || token == SWIG_TOKEN_LONGDOUBLE) {
errmsg = "Floating point constant in preprocessor expression";
*error = 1;
return 0;
diff --git a/Source/Swig/scanner.c b/Source/Swig/scanner.c
index 7ef3293..63d38ec 100644
--- a/Source/Swig/scanner.c
+++ b/Source/Swig/scanner.c
@@ -1121,7 +1121,7 @@
return SWIG_TOKEN_FLOAT;
} else if ((c == 'l') || (c == 'L')) {
Delitem(s->text, DOH_END);
- return SWIG_TOKEN_DOUBLE;
+ return SWIG_TOKEN_LONGDOUBLE;
} else {
retract(s, 1);
return (SWIG_TOKEN_DOUBLE);
@@ -1258,7 +1258,7 @@
return SWIG_TOKEN_FLOAT;
} else if ((c == 'l') || (c == 'L')) {
Delitem(s->text, DOH_END);
- return SWIG_TOKEN_DOUBLE;
+ return SWIG_TOKEN_LONGDOUBLE;
} else {
retract(s, 1);
return SWIG_TOKEN_DOUBLE;
diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c
index 5085719..fdc83ca 100644
--- a/Source/Swig/stype.c
+++ b/Source/Swig/stype.c
@@ -134,6 +134,9 @@
case T_DOUBLE:
return NewString("double");
break;
+ case T_LONGDOUBLE:
+ return NewString("long double");
+ break;
case T_COMPLEX:
return NewString("_Complex");
break;
diff --git a/Source/Swig/swigscan.h b/Source/Swig/swigscan.h
index 6c9d1ff..08c9085 100644
--- a/Source/Swig/swigscan.h
+++ b/Source/Swig/swigscan.h
@@ -53,26 +53,27 @@
#define SWIG_TOKEN_ID 15 /* identifier */
#define SWIG_TOKEN_FLOAT 16 /* 3.1415F */
#define SWIG_TOKEN_DOUBLE 17 /* 3.1415 */
-#define SWIG_TOKEN_INT 18 /* 314 */
-#define SWIG_TOKEN_UINT 19 /* 314U */
-#define SWIG_TOKEN_LONG 20 /* 314L */
-#define SWIG_TOKEN_ULONG 21 /* 314UL */
-#define SWIG_TOKEN_CHAR 22 /* 'charconst' */
-#define SWIG_TOKEN_PERIOD 23 /* . */
-#define SWIG_TOKEN_AT 24 /* @ */
-#define SWIG_TOKEN_DOLLAR 25 /* $ */
-#define SWIG_TOKEN_CODEBLOCK 26 /* %{ ... %} ... */
-#define SWIG_TOKEN_RSTRING 27 /* `charconst` */
-#define SWIG_TOKEN_LONGLONG 28 /* 314LL */
-#define SWIG_TOKEN_ULONGLONG 29 /* 314ULL */
-#define SWIG_TOKEN_QUESTION 30 /* ? */
-#define SWIG_TOKEN_COMMENT 31 /* C or C++ comment */
-#define SWIG_TOKEN_BOOL 32 /* true or false */
-#define SWIG_TOKEN_WSTRING 33 /* L"str" */
-#define SWIG_TOKEN_WCHAR 34 /* L'c' */
-#define SWIG_TOKEN_ELLIPSIS 35 /* ... */
-#define SWIG_TOKEN_LLBRACKET 36 /* [[ */
-#define SWIG_TOKEN_RRBRACKET 37 /* ]] */
+#define SWIG_TOKEN_LONGDOUBLE 18 /* 3.1415L */
+#define SWIG_TOKEN_INT 19 /* 314 */
+#define SWIG_TOKEN_UINT 20 /* 314U */
+#define SWIG_TOKEN_LONG 21 /* 314L */
+#define SWIG_TOKEN_ULONG 22 /* 314UL */
+#define SWIG_TOKEN_CHAR 23 /* 'charconst' */
+#define SWIG_TOKEN_PERIOD 24 /* . */
+#define SWIG_TOKEN_AT 25 /* @ */
+#define SWIG_TOKEN_DOLLAR 26 /* $ */
+#define SWIG_TOKEN_CODEBLOCK 27 /* %{ ... %} ... */
+#define SWIG_TOKEN_RSTRING 28 /* `charconst` */
+#define SWIG_TOKEN_LONGLONG 29 /* 314LL */
+#define SWIG_TOKEN_ULONGLONG 30 /* 314ULL */
+#define SWIG_TOKEN_QUESTION 31 /* ? */
+#define SWIG_TOKEN_COMMENT 32 /* C or C++ comment */
+#define SWIG_TOKEN_BOOL 33 /* true or false */
+#define SWIG_TOKEN_WSTRING 34 /* L"str" */
+#define SWIG_TOKEN_WCHAR 35 /* L'c' */
+#define SWIG_TOKEN_ELLIPSIS 36 /* ... */
+#define SWIG_TOKEN_LLBRACKET 37 /* [[ */
+#define SWIG_TOKEN_RRBRACKET 38 /* ]] */
#define SWIG_TOKEN_ILLEGAL 99
#define SWIG_TOKEN_ERROR -1