Subject: bug#49755: [PATCH][bug 34151, 42393, 44795, 49755, 45205, 55073] Fix lex/yacc C++ tests on Solaris/SunOS

From: Bogdan <[email-masked]>
Date: Sun, 16 Apr 2023 18:37:28 +0200

Hi all.

  The Solaris/SunOS lex generates C++ code with functions properly 
wrapped into >extern "C"<, but only if:

- compiling as C++ (__cplusplus is #defined),

- the feature constant __EXTERN_C__ is #defined (probably meant just 
for the SunOS compiler, not for all).

Other compilers, like GCC/G++, obviously miss the SunOS-specific 
__EXTERN_C__ and thus miss >extern "C"<, declaring the yylex() 
function as C++ (the default). This doesn't need to be a problem, but:

- the function should be declared as the user code expects it (as C 
for C programs and as C++ for C++ programs),

- the Automake lex tests for C++ re-declare the function always as a C 
function.

  The re-declarations happens probably for good reason, like for lex 
implementations which don't declare the function in advance combined 
with C/C++ compilers which always require declarations. Unfortunately, 
having the same function declared as C++ (default) first and then 
later as C causes compiler errors.

  The attached patch corrects the declarations in the following way:

- if we're in C++ mode and __EXTERN_C__ is declared (so, we're on a 
SunOS with their compiler), declare the function as C in C++ mode 
(i.e., use >extern "C"<), just like the SunOS lex does,

- if we're in C++ mode and __EXTERN_C__ is NOT declared, but also 
"__sun" is not declared (so, we're NOT on a SunOS), still assume C++ 
mode, but a different system and declare the function as C in C++ mode 
(i.e., use >extern "C"<) to support other compilers,

- if we're in C++ mode and __EXTERN_C__ is NOT declared, but also 
"__sun" IS declared (so, we ARE on a SunOS, but not using their 
compiler), declare the function as C++ in C++ mode, just like the 
SunOS lex does,

- if we're NOT in C++ mode, declare the function as C. Not the case in 
these tests, though.

  This should match what the SunOS lex/compiler do and expect which 
not braking other systems (re-checked on my Linux - works).

  Verified that the defect exists on a Solaris 11.4 Build 15 (SunOS 
5.11, GCC 7.3.0, amd64) and that the patch fixes it.

  Furthermore, I checked how GCC manages the declarations of standard 
C functions in C++. Seems so simple as saying:

	using std::some_c_library_function_name;

  which the SunOS library (or maybe just the old GCC library there) is 
not doing.
  So, it just takes this to fix the missing prototypes in C++ mode.

  In short, the patch:
- fixes the remaining part of 
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34151,
- fixes the remaining part of 
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=42393 
(t/silent-many-languages.sh works for me),
- fixes https://debbugs.gnu.org/cgi/bugreport.cgi?bug=44795,
- fixes https://debbugs.gnu.org/cgi/bugreport.cgi?bug=49755,
- partially fixes https://debbugs.gnu.org/cgi/bugreport.cgi?bug=45205,
- partially fixes https://debbugs.gnu.org/cgi/bugreport.cgi?bug=55073.

  Fortunately, these parts are just problems with the tests 
themselves, not with Automake in general.

-- 
Regards - Bogdan ('bogdro') D.                 (GNU/Linux & FreeDOS)
X86 assembly (DOS, GNU/Linux):    http://bogdro.evai.pl/index-en.php
Soft(EN): http://bogdro.evai.pl/soft  http://bogdro.evai.pl/soft4asm
www.Xiph.org  www.TorProject.org  www.LibreOffice.org  www.GnuPG.org

From b8813c99e220073b528511f47cc0c4cfd8ef1c20 Mon Sep 17 00:00:00 2001
From: Bogdan Drozdowski <>
Date: Sun, 16 Apr 2023 17:39:26 +0200
Subject: [PATCH] Fix lex/yacc C++ tests on SunOS

---
 t/lex-clean-cxx.sh  | 10 ++++++++--
 t/lex-depend-cxx.sh |  5 ++++-
 t/yacc-cxx.sh       |  3 +++
 t/yacc-d-cxx.sh     |  3 +++
 t/yacc-mix-c-cxx.sh |  3 +++
 5 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/t/lex-clean-cxx.sh b/t/lex-clean-cxx.sh
index 3632d5c87..afbacf392 100644
--- a/t/lex-clean-cxx.sh
+++ b/t/lex-clean-cxx.sh
@@ -54,7 +54,10 @@ END
 cat > parsefoo.lxx << 'END'
 %{
 #define YY_DECL int yylex (void)
-extern "C" YY_DECL;
+#if (defined __cplusplus) && ((!defined __sun) || (defined __EXTERN_C__))
+extern "C"
+#endif
+YY_DECL;
 #define YY_NO_UNISTD_H 1
 int isatty (int fd) { return 0; }
 %}
@@ -71,7 +74,10 @@ cp parsefoo.lxx parsebar.ll
 
 cat > mainfoo.cc << 'END'
 // This file should contain valid C++ but invalid C.
-extern "C" int yylex (void);
+#if (defined __cplusplus) && ((!defined __sun) || (defined __EXTERN_C__))
+extern "C"
+#endif
+int yylex (void);
 using namespace std;
 int main (int argc, char **argv)
 {
diff --git a/t/lex-depend-cxx.sh b/t/lex-depend-cxx.sh
index 60615a54e..817450fc0 100644
--- a/t/lex-depend-cxx.sh
+++ b/t/lex-depend-cxx.sh
@@ -47,7 +47,10 @@ END
 cat > joe.ll << 'END'
 %{
 #define YY_DECL int yylex (void)
-extern "C" YY_DECL;
+#if (defined __cplusplus) && ((!defined __sun) || (defined __EXTERN_C__))
+extern "C"
+#endif
+YY_DECL;
 #define YY_NO_UNISTD_H 1
 int isatty (int fd) { return 0; }
 %}
diff --git a/t/yacc-cxx.sh b/t/yacc-cxx.sh
index 1bf75a975..5b385870c 100644
--- a/t/yacc-cxx.sh
+++ b/t/yacc-cxx.sh
@@ -49,6 +49,9 @@ cat > parse1.yy << 'END'
 // Valid C++, but deliberately invalid C.
 #include <cstdio>
 #include <cstdlib>
+using std::exit;
+using std::free;
+using std::malloc;
 // "std::" qualification required by Sun C++ 5.9.
 int yylex (void) { return std::getchar (); }
 void yyerror (const char *s) {}
diff --git a/t/yacc-d-cxx.sh b/t/yacc-d-cxx.sh
index 56f43c940..576e8e2aa 100644
--- a/t/yacc-d-cxx.sh
+++ b/t/yacc-d-cxx.sh
@@ -31,6 +31,9 @@ write_parse ()
     #include <stdlib.h>
     // Valid C++, but deliberately invalid C.
     #include <cstdlib>
+    using std::exit;
+    using std::free;
+    using std::malloc;
     #include "$header"
     int yylex (void) { return 0; }
     void yyerror (const char *s) {}
diff --git a/t/yacc-mix-c-cxx.sh b/t/yacc-mix-c-cxx.sh
index a73935c39..7c44e0926 100644
--- a/t/yacc-mix-c-cxx.sh
+++ b/t/yacc-mix-c-cxx.sh
@@ -86,6 +86,9 @@ cat > parse.yy <<'END'
 // https://bugs.gnu.org/20031
 #include <stdlib.h>
 // Valid C++, but deliberately invalid C.
+using std::exit;
+using std::free;
+using std::malloc;
 #include <cstdlib>
 #include "parse.hh"
 int yylex (void) { return 0; }
-- 
2.35.1