diff options
author | Olly Betts <olly@survex.com> | 2023-04-19 16:00:03 +1200 |
---|---|---|
committer | Olly Betts <olly@survex.com> | 2023-04-19 16:00:03 +1200 |
commit | 26dfe3394810a72e85c4c52ee568ff44cfbcac76 (patch) | |
tree | 19f20506c2605a45b1a7bc6bff7f8be35161711d | |
parent | 7df0d05e875bd96d0e3a64e2fe3c968a5f160375 (diff) | |
parent | 8f946309cce18ab14506f2bacb3c7954ff415471 (diff) | |
download | swig-26dfe3394810a72e85c4c52ee568ff44cfbcac76.tar.gz |
Merge branch 'macro-partial-expansion'
-rw-r--r-- | CHANGES.current | 6 | ||||
-rw-r--r-- | Examples/test-suite/preproc_defined.i | 28 | ||||
-rw-r--r-- | Examples/test-suite/python/preproc_defined_runme.py | 9 | ||||
-rw-r--r-- | Source/Preprocessor/cpp.c | 49 |
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); |