As noted in Bugzilla (and pointed out in LLVM's bugzilla by Richard Smith) we check for a ::gets() declaration with the default -std=gnu++14 mode, so for glibc we don't find it, and then we declare it ourselves in <cstdio> even though it's not meant to exist in C++14.
This adjusts the check to use C++11, and doesn't declare it for C++14 and later. I think this fixes the regression, without introducing any new problems. Please take a look and double-check I haven't missed something. PR libstdc++/77795 * acinclude.m4 (GLIBCXX_CHECK_STDIO_PROTO): Use -std=gnu++11 to check for gets. * config.h.in: Regenerate. * configure: Regenerate. * include/c_global/cstdio [!_GLIBCXX_HAVE_GETS] (gets): Only declare for C++98 and C++11. * include/c_std/cstdio [!_GLIBCXX_HAVE_GETS] (gets): Likewise. * testsuite/27_io/headers/cstdio/functions_neg.cc: New test. I think we could also get rid of the hack in config/os/gnu-linux/os_defines.h because it doesn't do anything: // Provide a declaration for the possibly deprecated gets function, as // glibc 2.15 and later does not declare gets for ISO C11 when // __GNU_SOURCE is defined. #if __GLIBC_PREREQ(2,15) && defined(_GNU_SOURCE) # undef _GLIBCXX_HAVE_GETS #endif Firstly, neither 2.15 nor 2.16.0 has this issue (only some 2.15.xxx versions built from version control rather than from official releases). So we only need to check for exactly 2.15, rather than anything >= 2.15. Secondly, that file is included *before* c++config.h defines _GLIBCXX_HAVE_GETS so the #undef doesn't work anyway. So I think we might as well just get rid of it. If someone builds libstdc++ against a 2.15.xxx without the gets declaration then we don't define _GLIBCXX_HAVE_GETS and so we declare ::gets in <cstdio>. If someone builds libstdc++ against 2.15 and then upgrades to a glibc 2.15.xxx without gets they'll have problems, because _GLIBCXX_HAVE_GETS will be defined to 1, but they won't have a gets declaration in the glibc <stdio.h>. So don't do that. If we really needed to we could support that by changing os_defines.h to: #if __GLIBC__ == 2 && __GLIBC_MINOR__ == 15 && defined(_GNU_SOURCE) # define _GLIBCXX_NEED_GETS_DECL #endif And then in <cstdio>: #if __cplusplus <= 201103L #if !defined(_GLIBCXX_HAVE_GETS) || defined(_GLIBCXX_NEED_GETS_DECL) extern "C" char* gets (char* __s) __attribute__((__deprecated__)); #endif #endif But we haven't needed that until now, so I'd prefer to just drop the hack in os_defines.h
commit fb65b330f57bf6b6e64fa3a7728e185ff4e45918 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Sep 30 10:26:35 2016 +0100 libstdc++/77795 Only declare ::gets for C++98 and C++11 PR libstdc++/77795 * acinclude.m4 (GLIBCXX_CHECK_STDIO_PROTO): Use -std=gnu++11 to check for gets. * config.h.in: Regenerate. * configure: Regenerate. * include/c_global/cstdio [!_GLIBCXX_HAVE_GETS] (gets): Only declare for C++98 and C++11. * include/c_std/cstdio [!_GLIBCXX_HAVE_GETS] (gets): Likewise. * testsuite/27_io/headers/cstdio/functions_neg.cc: New test. diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index ffead7d..d0ee45f 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -2153,6 +2153,10 @@ AC_DEFUN([GLIBCXX_CHECK_STDIO_PROTO], [ AC_LANG_SAVE AC_LANG_CPLUSPLUS + # Use C++11 because a conforming <stdio.h> won't define gets for C++14, + # and we don't need a declaration for C++14 anyway. + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=gnu++11" AC_MSG_CHECKING([for gets declaration]) AC_CACHE_VAL(glibcxx_cv_gets, [ @@ -2168,10 +2172,11 @@ AC_DEFUN([GLIBCXX_CHECK_STDIO_PROTO], [ )]) if test $glibcxx_cv_gets = yes; then - AC_DEFINE(HAVE_GETS, 1, [Define if gets is available in <stdio.h>.]) + AC_DEFINE(HAVE_GETS, 1, [Define if gets is available in <stdio.h> before C++14.]) fi AC_MSG_RESULT($glibcxx_cv_gets) + CXXFLAGS="$ac_save_CXXFLAGS" AC_LANG_RESTORE ]) diff --git a/libstdc++-v3/include/c_global/cstdio b/libstdc++-v3/include/c_global/cstdio index 920d109..86d524f 100644 --- a/libstdc++-v3/include/c_global/cstdio +++ b/libstdc++-v3/include/c_global/cstdio @@ -44,7 +44,7 @@ #ifndef _GLIBCXX_CSTDIO #define _GLIBCXX_CSTDIO 1 -#ifndef _GLIBCXX_HAVE_GETS +#if __cplusplus <= 201103L && !defined(_GLIBCXX_HAVE_GETS) extern "C" char* gets (char* __s) __attribute__((__deprecated__)); #endif diff --git a/libstdc++-v3/include/c_std/cstdio b/libstdc++-v3/include/c_std/cstdio index a4119ba..549004c 100644 --- a/libstdc++-v3/include/c_std/cstdio +++ b/libstdc++-v3/include/c_std/cstdio @@ -44,7 +44,7 @@ #include <bits/c++config.h> #include <stdio.h> -#ifndef _GLIBCXX_HAVE_GETS +#if __cplusplus <= 201103L && !defined(_GLIBCXX_HAVE_GETS) extern "C" char* gets (char* __s) __attribute__((__deprecated__)); #endif diff --git a/libstdc++-v3/testsuite/27_io/headers/cstdio/functions_neg.cc b/libstdc++-v3/testsuite/27_io/headers/cstdio/functions_neg.cc new file mode 100644 index 0000000..f9e5f86 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/headers/cstdio/functions_neg.cc @@ -0,0 +1,25 @@ +// { dg-do compile { target c++14 } } + +// Copyright (C) 2007-2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <cstdio> + +namespace gnu +{ + using std::gets; // { dg-error "has not been declared" } +}