From de4e3b454e23af3f26f8c2ea670482bef738e983 Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Fri, 21 Apr 2023 07:38:52 +1200 Subject: Fix #ifdef and #ifndef to work inside a %define Previously they were silently ignored in this context (but #if defined already worked here if you need a workaround which works for older versions). Fixes #2183 --- CHANGES.current | 6 ++++++ Examples/test-suite/preproc_defined.i | 35 ++++++++++++++++++++++++++++++++++ Source/Preprocessor/cpp.c | 36 ++++++++++++++++++++++++++++------- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/CHANGES.current b/CHANGES.current index ed80e145e..5dfc249e9 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-21: olly + #2183 Fix #ifdef and #ifndef to work inside a %define. Previously + they were silently ignored in this context (but #if defined already + worked here if you need a workaround which works for older + versions). + 2023-04-20: erezgeva [Go] #2533 Implement argcargv.i library for Go. diff --git a/Examples/test-suite/preproc_defined.i b/Examples/test-suite/preproc_defined.i index 9ae884691..f000446c4 100644 --- a/Examples/test-suite/preproc_defined.i +++ b/Examples/test-suite/preproc_defined.i @@ -151,3 +151,38 @@ const int y = 0; #undef y #undef x + +/* Regression test for #ifdef and #ifndef not working inside a %define. + * https://github.com/swig/swig/issues/2183 + */ +#undef THISMACROISNOTDEFINED /* Make sure! */ +#define THISMACROISDEFINED + +%define %test() + +#ifdef THISMACROISNOTDEFINED +# error #ifdef inside percent-define failed +#endif +#ifndef THISMACROISDEFINED +# error #ifndef inside percent-define failed +#endif +/* Check pre-defined macro too. */ +#ifndef SWIG +# error #ifndef inside percent-define failed +#endif + +/* These cases already worked, but should still have test coverage. */ +#if defined THISMACROISNOTDEFINED +# error #if defined inside percent-define failed +#endif +#if !defined THISMACROISDEFINED +# error #if !defined inside percent-define failed +#endif +/* Check pre-defined macro too. */ +#if !defined SWIG +# error #if !defined inside percent-define failed +#endif + +%enddef + +%test() diff --git a/Source/Preprocessor/cpp.c b/Source/Preprocessor/cpp.c index 55058fc13..ae1e2ecb5 100644 --- a/Source/Preprocessor/cpp.c +++ b/Source/Preprocessor/cpp.c @@ -1191,14 +1191,36 @@ static DOH *Preprocessor_replace(DOH *s, DOH *line_file) { } else if (Equal(kpp_hash_if, id) || Equal(kpp_hash_elif, id)) { expand_defined_operator = 1; Append(ns, id); - /* - } else if (Equal("%#if", id) || Equal("%#ifdef", id)) { - Swig_warning(998, Getfile(s), Getline(s), "Found: %s preprocessor directive.\n", id); - Append(ns, id); } else if (Equal("#ifdef", id) || Equal("#ifndef", id)) { - Swig_warning(998, Getfile(s), Getline(s), "The %s preprocessor directive does not work in macros, try #if instead.\n", id); - Append(ns, id); - */ + /* Evaluate the defined-ness check and substitute `#if 0` or `#if 1`. */ + int allow = 0; + skip_whitespace(s, 0); + c = Getc(s); + if (isidchar(c)) { + DOH *arg = NewStringEmpty(); + Putc(c, arg); + while (((c = Getc(s)) != EOF)) { + if (!isidchar(c)) { + Ungetc(c, s); + break; + } + Putc(c, arg); + } + if (Equal("#ifdef", id)) { + if (Getattr(symbols, arg)) allow = 1; + } else { + if (!Getattr(symbols, arg)) allow = 1; + } + Delete(arg); + } else { + Ungetc(c, s); + Swig_error(Getfile(s), Getline(s), "Missing identifier for %s.\n", id); + } + if (allow) { + Append(ns, "#if 1"); + } else { + Append(ns, "#if 0"); + } } else if ((m = Getattr(symbols, id))) { /* See if the macro is defined in the preprocessor symbol table */ DOH *args = 0; -- cgit v1.2.1