summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlly Betts <olly@survex.com>2023-04-19 16:00:03 +1200
committerOlly Betts <olly@survex.com>2023-04-19 16:00:03 +1200
commit26dfe3394810a72e85c4c52ee568ff44cfbcac76 (patch)
tree19f20506c2605a45b1a7bc6bff7f8be35161711d
parent7df0d05e875bd96d0e3a64e2fe3c968a5f160375 (diff)
parent8f946309cce18ab14506f2bacb3c7954ff415471 (diff)
downloadswig-26dfe3394810a72e85c4c52ee568ff44cfbcac76.tar.gz
Merge branch 'macro-partial-expansion'
-rw-r--r--CHANGES.current6
-rw-r--r--Examples/test-suite/preproc_defined.i28
-rw-r--r--Examples/test-suite/python/preproc_defined_runme.py9
-rw-r--r--Source/Preprocessor/cpp.c49
4 files changed, 76 insertions, 16 deletions
diff --git a/CHANGES.current b/CHANGES.current
index 41dbcf559..cbfe89da9 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,6 +7,12 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.0 (in progress)
===========================
+2023-04-19: mmomtchev
+ https://sourceforge.net/p/swig/bugs/1163/ #2525 Fix preprocessor
+ expansion when a macro expands to the name of another macro which
+ takes parameters from the input following the original macro
+ expansion.
+
2023-04-19: wildmaples
[Ruby] #2527 Fix "undefining the allocator of T_DATA" warning seen
with Ruby 3.2.
diff --git a/Examples/test-suite/preproc_defined.i b/Examples/test-suite/preproc_defined.i
index 5ebf0a099..401666806 100644
--- a/Examples/test-suite/preproc_defined.i
+++ b/Examples/test-suite/preproc_defined.i
@@ -123,3 +123,31 @@ void another_macro_checking(void) {
#if 0
# wobble wobble
#endif
+
+/* Regression test for https://sourceforge.net/p/swig/bugs/1163/
+ * ONE(1)(2) should expand to `2` but SWIG was expanding it to `TWO(2)`
+ * which results in the generated C wrapper failing to compile.
+ */
+#define ONE(X) TWO
+#define TWO(X) X
+%constant int a = ONE(1)(2);
+#define XXX TWO
+%constant int b = XXX(42);
+#undef ONE
+#undef TWO
+
+/*
+ * The behaviour of Self-Referential Macros is defined
+ * https://gcc.gnu.org/onlinedocs/gcc-4.8.5/cpp/Self-Referential-Macros.html
+ */
+%inline %{
+int y = 0;
+%}
+
+#define x (4 + y)
+#define y (2 * x)
+
+%constant int z = y;
+
+#undef y
+#undef x
diff --git a/Examples/test-suite/python/preproc_defined_runme.py b/Examples/test-suite/python/preproc_defined_runme.py
index af46816be..37441db52 100644
--- a/Examples/test-suite/python/preproc_defined_runme.py
+++ b/Examples/test-suite/python/preproc_defined_runme.py
@@ -9,3 +9,12 @@ d.defined = 10
preproc_defined.thing(10)
preproc_defined.stuff(10)
preproc_defined.bumpf(10)
+
+if preproc_defined.a != 2:
+ raise RuntimeError
+
+if preproc_defined.b != 42:
+ raise RuntimeError
+
+if preproc_defined.z != 8:
+ raise RuntimeError
diff --git a/Source/Preprocessor/cpp.c b/Source/Preprocessor/cpp.c
index 10faa17d5..55058fc13 100644
--- a/Source/Preprocessor/cpp.c
+++ b/Source/Preprocessor/cpp.c
@@ -42,7 +42,7 @@ static const String * macro_start_file = 0;
/* Test a character to see if it valid in an identifier (after the first letter) */
#define isidchar(c) ((isalnum(c)) || (c == '_') || (c == '$'))
-static DOH *Preprocessor_replace(DOH *);
+static DOH *Preprocessor_replace(DOH *, DOH *);
/* Skip whitespace */
static void skip_whitespace(String *s, String *out) {
@@ -707,7 +707,7 @@ static String *get_filename(String *str, int *sysfile) {
Putc(c, fn);
if (isspace(c))
Ungetc(c, str);
- preprocessed_str = Preprocessor_replace(fn);
+ preprocessed_str = Preprocessor_replace(fn, NULL);
Seek(preprocessed_str, 0, SEEK_SET);
Delete(fn);
@@ -785,7 +785,7 @@ bad:
* of error occurred.
* name - name of the macro
* args - arguments passed to the macro
- * line_file - only used for line/file name when reporting errors
+ * line_file - global context, used for line/file name when reporting errors
* ----------------------------------------------------------------------------- */
static String *expand_macro(String *name, List *args, String *line_file) {
@@ -903,7 +903,7 @@ static String *expand_macro(String *name, List *args, String *line_file) {
DOH *arg, *aname;
String *reparg;
arg = Getitem(args, i); /* Get an argument value */
- reparg = Preprocessor_replace(arg);
+ reparg = Preprocessor_replace(arg, NULL);
aname = Getitem(margs, i); /* Get macro argument name */
if (strstr(Char(ns), "\001")) {
/* Try to replace a quoted version of the argument */
@@ -1009,7 +1009,7 @@ static String *expand_macro(String *name, List *args, String *line_file) {
/* Expand this macro even further */
Setattr(macro, kpp_expanded, "1");
- e = Preprocessor_replace(ns);
+ e = Preprocessor_replace(ns, line_file);
Delattr(macro, kpp_expanded);
Delete(ns);
@@ -1047,7 +1047,7 @@ static String *expand_macro(String *name, List *args, String *line_file) {
}
/* -----------------------------------------------------------------------------
- * DOH *Preprocessor_replace(DOH *s)
+ * DOH *Preprocessor_replace(DOH *s, DOH *line_file)
*
* Performs a macro substitution on a string s. Returns a new string with
* substitutions applied. This function works by walking down s and looking
@@ -1057,7 +1057,7 @@ static String *expand_macro(String *name, List *args, String *line_file) {
/* #define SWIG_PUT_BUFF */
-static DOH *Preprocessor_replace(DOH *s) {
+static DOH *Preprocessor_replace(DOH *s, DOH *line_file) {
DOH *ns, *symbols, *m;
int c, i, state = 0;
String *id = NewStringEmpty();
@@ -1280,14 +1280,31 @@ static DOH *Preprocessor_replace(DOH *s) {
Replaceall(fn, "\\", "\\\\");
Printf(ns, "\"%s\"", fn);
Delete(fn);
- } else if (Getattr(symbols, id)) {
- DOH *e;
+ } else if ((m = Getattr(symbols, id))) {
/* Yes. There is a macro here */
+ /* If it expects arguments, they must come from `line_file` */
+ DOH *args = 0;
+ DOH *e;
+ int macro_additional_lines = 0;
/* See if the macro expects arguments */
- e = expand_macro(id, 0, s);
- if (e)
+ if (Getattr(m, kpp_args) && line_file) {
+ /* Yep. We need to go find the arguments and do a substitution */
+ int line = Getline(line_file);
+ args = find_args(line_file, 1, id);
+ macro_additional_lines = Getline(line_file) - line;
+ assert(macro_additional_lines >= 0);
+ } else {
+ args = 0;
+ }
+ e = expand_macro(id, args, s);
+ if (e) {
Append(ns, e);
+ }
+ while (macro_additional_lines--) {
+ Putc('\n', ns);
+ }
Delete(e);
+ Delete(args);
} else {
Append(ns, id);
}
@@ -1343,7 +1360,7 @@ static void add_chunk(DOH *ns, DOH *chunk, int allow) {
DOH *echunk;
Seek(chunk, 0, SEEK_SET);
if (allow) {
- echunk = Preprocessor_replace(chunk);
+ echunk = Preprocessor_replace(chunk, NULL);
addline(ns, echunk, allow);
Delete(echunk);
} else {
@@ -1614,7 +1631,7 @@ String *Preprocessor_parse(String *s) {
copy_location(m, v);
if (Len(v)) {
Swig_error_silent(1);
- v1 = Preprocessor_replace(v);
+ v1 = Preprocessor_replace(v, NULL);
Swig_error_silent(0);
/* Printf(stdout,"checking '%s'\n", v1); */
if (!checkpp_id(v1)) {
@@ -1696,7 +1713,7 @@ String *Preprocessor_parse(String *s) {
int val;
String *sval;
expand_defined_operator = 1;
- sval = Preprocessor_replace(value);
+ sval = Preprocessor_replace(value, NULL);
start_level = level;
Seek(sval, 0, SEEK_SET);
/* Printf(stdout,"Evaluating '%s'\n", sval); */
@@ -1732,7 +1749,7 @@ String *Preprocessor_parse(String *s) {
int val;
String *sval;
expand_defined_operator = 1;
- sval = Preprocessor_replace(value);
+ sval = Preprocessor_replace(value, NULL);
Seek(sval, 0, SEEK_SET);
if (Len(sval) > 0) {
val = Preprocessor_expr(sval, &e);
@@ -1823,7 +1840,7 @@ String *Preprocessor_parse(String *s) {
if (*c) {
if (strncmp(c, "nowarn=", 7) == 0) {
String *val = NewString(c + 7);
- String *nowarn = Preprocessor_replace(val);
+ String *nowarn = Preprocessor_replace(val, NULL);
Swig_warnfilter(nowarn, 1);
Delete(nowarn);
Delete(val);