summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlly Betts <olly@survex.com>2023-04-21 07:38:52 +1200
committerOlly Betts <olly@survex.com>2023-04-21 07:40:25 +1200
commitde4e3b454e23af3f26f8c2ea670482bef738e983 (patch)
tree33fd3903a69263b03bd0a907c894044c8797087a
parent3275331886192da4ce2047d52be91526f5608c4f (diff)
downloadswig-de4e3b454e23af3f26f8c2ea670482bef738e983.tar.gz
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
-rw-r--r--CHANGES.current6
-rw-r--r--Examples/test-suite/preproc_defined.i35
-rw-r--r--Source/Preprocessor/cpp.c36
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;