On 10/17/16 20:05, Joseph Myers wrote:
> On Sun, 16 Oct 2016, Bernd Edlinger wrote:
>
>> Second, the declaration in the glibc header files simply look wrong,
>> because the type of argv, and envp is "char *const *" while the
>> builtin function wants "const char**", thus only the array of char*
>> itself is const, not the actual char stings they point to.
>
> char *const * is the POSIX type.  (It can't be const char ** or const char
> *const * because you can't convert char ** implicitly to those types in
> ISO C.)  You'd need to check the list archives for rationale for the
> built-in functions doing something different.
>

Yes, that was discussed here:
https://gcc.gnu.org/ml/gcc-patches/2004-03/msg01148.html

No mention why the BT_PTR_CONST_TYPE does not match the posix type.
But the right types were used on __gcov_execv/e/p stubs, so the author
did know the right types at least.

So I think that was broken from the beginning, but that was hidden by
the loose checking in the C FE and not warning in the C++ FE when
prototypes don't match.

>> Third, in C the  builtins are not diagnosed, because C does only look
>> at the mode of the parameters see match_builtin_function_types in
>> c/c-decl.c, which may itself be wrong, because that makes an ABI
>> decision dependent on the mode of the parameter.
>
> The matching needs to be loose because of functions using types such as
> FILE * where the compiler doesn't know the exact contents of the type when
> processing built-in function definitions.  (Historically there were also
> issues with pre-ISO headers, but that may be less relevant now.)
>

The C++ FE has exactly the same problem with FILE* and struct tm*
but it solves it differently and "learns" the type but only for FILE*
and with this patch also for const struct tm*.  It is a lot more
restrictive than C, but that is because of the ++ ;)

Well in that case the posix functions have to use the prototypes
from POSIX.1.2008 although their rationale is a bit silly...

This updated patch fixes the prototype of execv/p/e,
and adds a new test case that checks that no type conflict
exists in the execve built-in any more.

Now we have no -Wsystem-headers warnings with glibc-headers any more.
And the gcov builtin also is working with C++.

Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
Is it OK for trunk?


Thanks
Bernd.
gcc:
2016-10-17  Bernd Edlinger  <bernd.edlin...@hotmail.de>

        PR c++/71973
        * doc/invoke.texi: Document -Wbuiltin-function-redefined.
        * builtin-types.def (BT_CONST_TM_PTR): New primitive type.
        (BT_PTR_CONST_STRING): Updated.
        (BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_PTR): Removed.
        (BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_TM_PTR): New function type.
        * builtins.def (strftime): Update builtin function.
        * tree-core.h (TI_CONST_TM_PTR_TYPE): New enum value.
        * tree.h (const_tm_ptr_type_node): New type node.
        * tree.c (free_lang_data, build_common_tree_nodes): Initialize
        const_tm_ptr_type_node.

c-family:
2016-10-17  Bernd Edlinger  <bernd.edlin...@hotmail.de>

        PR c++/71973
        * c.opt (Wbuiltin-function-redefined): New warning.
        * c-common.c (c_common_nodes_and_builtins): Initialize
        const_tm_ptr_type_node.

cp:
2016-10-17  Bernd Edlinger  <bernd.edlin...@hotmail.de>

        PR c++/71973
        * decl.c (duplicate_decls): Warn when a built-in function is redefined.
        Don't overload builtin functions with C++ functions.
        Handle const_tm_ptr_type_node like file_ptr_node.
        Copy the TREE_NOTHROW flag unmodified to the old decl.

lto:
2016-10-17  Bernd Edlinger  <bernd.edlin...@hotmail.de>

        PR c++/71973
        * lto-lang.c (lto_init): Assert const_tm_ptr_type_node is sane.

testsuite:
2016-10-17  Bernd Edlinger  <bernd.edlin...@hotmail.de>

        PR c++/71973
        * g++.dg/pr71973-1.C: New test.
        * g++.dg/pr71973-2.C: New test.
        * g++.dg/pr71973-3.C: New test.
        * g++.dg/lookup/extern-c-redecl4.C: Adjust test expectations.
Index: gcc/builtin-types.def
===================================================================
--- gcc/builtin-types.def	(revision 241271)
+++ gcc/builtin-types.def	(working copy)
@@ -103,6 +103,7 @@ DEF_PRIMITIVE_TYPE (BT_COMPLEX_LONGDOUBLE, complex
 
 DEF_PRIMITIVE_TYPE (BT_PTR, ptr_type_node)
 DEF_PRIMITIVE_TYPE (BT_FILEPTR, fileptr_type_node)
+DEF_PRIMITIVE_TYPE (BT_CONST_TM_PTR, const_tm_ptr_type_node)
 DEF_PRIMITIVE_TYPE (BT_CONST_PTR, const_ptr_type_node)
 DEF_PRIMITIVE_TYPE (BT_VOLATILE_PTR,
 		    build_pointer_type
@@ -146,7 +147,12 @@ DEF_PRIMITIVE_TYPE (BT_I16, builtin_type_for_size
 
 DEF_PRIMITIVE_TYPE (BT_BND, pointer_bounds_type_node)
 
-DEF_POINTER_TYPE (BT_PTR_CONST_STRING, BT_CONST_STRING)
+/* The C type `char * const *'.  */
+DEF_PRIMITIVE_TYPE (BT_PTR_CONST_STRING,
+		    build_pointer_type
+		     (build_qualified_type (string_type_node,
+					    TYPE_QUAL_CONST)))
+
 DEF_POINTER_TYPE (BT_PTR_UINT, BT_UINT)
 DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG)
 DEF_POINTER_TYPE (BT_PTR_ULONG, BT_ULONG)
@@ -511,8 +517,8 @@ DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZ
 		     BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
 DEF_FUNCTION_TYPE_4 (BT_FN_INT_STRING_SIZE_CONST_STRING_VALIST_ARG,
 		BT_INT, BT_STRING, BT_SIZE, BT_CONST_STRING, BT_VALIST_ARG)
-DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_PTR,
-		BT_SIZE, BT_STRING, BT_SIZE, BT_CONST_STRING, BT_CONST_PTR)
+DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_TM_PTR,
+		BT_SIZE, BT_STRING, BT_SIZE, BT_CONST_STRING, BT_CONST_TM_PTR)
 DEF_FUNCTION_TYPE_4 (BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE,
 		     BT_PTR, BT_PTR, BT_CONST_PTR, BT_SIZE, BT_SIZE)
 DEF_FUNCTION_TYPE_4 (BT_FN_PTR_PTR_INT_SIZE_SIZE,
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def	(revision 241271)
+++ gcc/builtins.def	(working copy)
@@ -866,7 +866,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_RETURN_ADDRESS, "
 DEF_GCC_BUILTIN        (BUILT_IN_SAVEREGS, "saveregs", BT_FN_PTR_VAR, ATTR_NULL)
 DEF_GCC_BUILTIN        (BUILT_IN_SETJMP, "setjmp", BT_FN_INT_PTR, ATTR_RT_NOTHROW_LEAF_LIST)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_STRFMON, "strfmon", BT_FN_SSIZE_STRING_SIZE_CONST_STRING_VAR, ATTR_FORMAT_STRFMON_NOTHROW_3_4)
-DEF_LIB_BUILTIN        (BUILT_IN_STRFTIME, "strftime", BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_PTR, ATTR_FORMAT_STRFTIME_NOTHROW_3_0)
+DEF_LIB_BUILTIN        (BUILT_IN_STRFTIME, "strftime", BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_TM_PTR, ATTR_FORMAT_STRFTIME_NOTHROW_3_0)
 DEF_GCC_BUILTIN        (BUILT_IN_TRAP, "trap", BT_FN_VOID, ATTR_NORETURN_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_UNREACHABLE, "unreachable", BT_FN_VOID, ATTR_CONST_NORETURN_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_UNWIND_INIT, "unwind_init", BT_FN_VOID, ATTR_NULL)
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 241271)
+++ gcc/c-family/c-common.c	(working copy)
@@ -4278,9 +4278,13 @@ c_common_nodes_and_builtins (void)
 	}
 
   if (c_dialect_cxx ())
-    /* For C++, make fileptr_type_node a distinct void * type until
-       FILE type is defined.  */
-    fileptr_type_node = build_variant_type_copy (ptr_type_node);
+    {
+      /* For C++, make fileptr_type_node a distinct void * type until
+	 FILE type is defined.  */
+      fileptr_type_node = build_variant_type_copy (ptr_type_node);
+      /* Likewise for const struct tm*.  */
+      const_tm_ptr_type_node = build_variant_type_copy (const_ptr_type_node);
+    }
 
   record_builtin_type (RID_VOID, NULL, void_type_node);
 
Index: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt	(revision 241271)
+++ gcc/c-family/c.opt	(working copy)
@@ -323,6 +323,10 @@ Wframe-address
 C ObjC C++ ObjC++ Var(warn_frame_address) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when __builtin_frame_address or __builtin_return_address is used unsafely.
 
+Wbuiltin-function-redefined
+C++ ObjC++ Var(warn_builtin_function_redefined) Warning LangEnabledBy(C++ ObjC++,Wall)
+Warn when a built-in function is redefined.
+
 Wbuiltin-macro-redefined
 C ObjC C++ ObjC++ CPP(warn_builtin_macro_redefined) CppReason(CPP_W_BUILTIN_MACRO_REDEFINED) Var(cpp_warn_builtin_macro_redefined) Init(1) Warning
 Warn when a built-in preprocessor macro is undefined or redefined.
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 241271)
+++ gcc/cp/decl.c	(working copy)
@@ -1489,10 +1489,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool
 	     explicitly declared.  */
 	  if (DECL_ANTICIPATED (olddecl))
 	    {
-	      /* Deal with fileptr_type_node.  FILE type is not known
-		 at the time we create the builtins.  */
 	      tree t1, t2;
 
+	      /* A new declaration doesn't match a built-in one unless it
+		 is also extern "C".  */
+	      gcc_assert (DECL_IS_BUILTIN (olddecl));
+	      gcc_assert (DECL_EXTERN_C_P (olddecl));
+	      if (!DECL_EXTERN_C_P (newdecl))
+		return NULL_TREE;
+
 	      for (t1 = TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
 		   t2 = TYPE_ARG_TYPES (TREE_TYPE (olddecl));
 		   t1 || t2;
@@ -1499,6 +1504,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool
 		   t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
 		if (!t1 || !t2)
 		  break;
+	        /* Deal with fileptr_type_node.  FILE type is not known
+		   at the time we create the builtins.  */
 		else if (TREE_VALUE (t2) == fileptr_type_node)
 		  {
 		    tree t = TREE_VALUE (t1);
@@ -1519,8 +1526,34 @@ duplicate_decls (tree newdecl, tree olddecl, bool
 			TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs;
 		      }
 		  }
+		/* Likewise for const struct tm*.  */
+		else if (TREE_VALUE (t2) == const_tm_ptr_type_node)
+		  {
+		    tree t = TREE_VALUE (t1);
+
+		    if (TYPE_PTR_P (t)
+			&& TYPE_IDENTIFIER (TREE_TYPE (t))
+			   == get_identifier ("tm")
+			&& compparms (TREE_CHAIN (t1), TREE_CHAIN (t2)))
+		      {
+			tree oldargs = TYPE_ARG_TYPES (TREE_TYPE (olddecl));
+
+			TYPE_ARG_TYPES (TREE_TYPE (olddecl))
+			  = TYPE_ARG_TYPES (TREE_TYPE (newdecl));
+			types_match = decls_match (newdecl, olddecl);
+			if (types_match)
+			  return duplicate_decls (newdecl, olddecl,
+						  newdecl_is_friend);
+			TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs;
+		      }
+		  }
 		else if (! same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
 		  break;
+
+	      warning_at (DECL_SOURCE_LOCATION (newdecl),
+			  OPT_Wbuiltin_function_redefined,
+			  "declaration of %q+#D conflicts with built-in "
+			  "declaration %q#D", newdecl, olddecl);
 	    }
 	  else if ((DECL_EXTERN_C_P (newdecl)
 		    && DECL_EXTERN_C_P (olddecl))
@@ -1574,7 +1607,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool
 
       /* Whether or not the builtin can throw exceptions has no
 	 bearing on this declarator.  */
-      TREE_NOTHROW (olddecl) = 0;
+      TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl);
 
       if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl))
 	{
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 241271)
+++ gcc/doc/invoke.texi	(working copy)
@@ -256,7 +256,7 @@ Objective-C and Objective-C++ Dialects}.
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
 -Wno-aggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
--Wno-attributes -Wbool-compare -Wbool-operation @gol
+-Wno-attributes -Wbool-compare -Wbool-operation -Wbuiltin-function-redefined @gol
 -Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat @gol
 -Wc++-compat -Wc++11-compat -Wc++14-compat -Wcast-align  -Wcast-qual  @gol
 -Wchar-subscripts -Wclobbered  -Wcomment -Wconditionally-supported  @gol
@@ -3673,6 +3673,7 @@ Options} and @ref{Objective-C and Objective-C++ Di
 -Warray-bounds=1 @r{(only with} @option{-O2}@r{)}  @gol
 -Wbool-compare  @gol
 -Wbool-operation  @gol
+-Wbuiltin-function-redefined @r{(C++ and Objective-C++ only)} @gol
 -Wc++11-compat  -Wc++14-compat@gol
 -Wchar-subscripts  @gol
 -Wcomment  @gol
@@ -5793,6 +5794,13 @@ unrecognized attributes, function attributes appli
 etc.  This does not stop errors for incorrect use of supported
 attributes.
 
+@item -Wbuiltin-function-redefined @r{(C++ and Objective-C++ only)}
+@opindex Wbuiltin-function-redefined
+@opindex Wno-builtin-function-redefined
+Do warn if built-in functions are redefined.  This option is only
+supported for C++ and Objective-C++.  It is implied by @option{-Wall},
+which can be disabled with @option{-Wno-builtin-function-redefined}.
+
 @item -Wno-builtin-macro-redefined
 @opindex Wno-builtin-macro-redefined
 @opindex Wbuiltin-macro-redefined
Index: gcc/lto/lto-lang.c
===================================================================
--- gcc/lto/lto-lang.c	(revision 241271)
+++ gcc/lto/lto-lang.c	(working copy)
@@ -1266,6 +1266,10 @@ lto_init (void)
      always use the C definition here in lto1.  */
   gcc_assert (fileptr_type_node == ptr_type_node);
   gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
+  /* Likewise for const struct tm*.  */
+  gcc_assert (const_tm_ptr_type_node == const_ptr_type_node);
+  gcc_assert (TYPE_MAIN_VARIANT (const_tm_ptr_type_node)
+	      == const_ptr_type_node);
 
   ptrdiff_type_node = integer_type_node;
 
Index: gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C	(revision 241271)
+++ gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C	(working copy)
@@ -3,7 +3,6 @@
 
 // { dg-options "" }
 // { dg-do compile }
-// { dg-final { scan-assembler "call\[\t \]+\[^\$\]*?_Z4forkv" { target i?86-*-* x86_64-*-* } } }
 
 class frok
 {
@@ -14,5 +13,5 @@ class frok
 void
 foo ()
 {
-  fork ();
+  fork (); // { dg-error "was not declared in this scope" }
 }
Index: gcc/testsuite/g++.dg/pr71973-1.C
===================================================================
--- gcc/testsuite/g++.dg/pr71973-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/pr71973-1.C	(working copy)
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-Wall -fdump-tree-eh" }
+
+extern "C"
+void fork () // { dg-warning "conflicts with built-in declaration" }
+__attribute__ ((__nothrow__));
+
+void foo () throw ()
+{
+  fork ();
+}
+
+// { dg-final { scan-tree-dump-not "eh_dispatch" "eh" } }
+// { dg-final { scan-tree-dump-not "resx" "eh" } }
Index: gcc/testsuite/g++.dg/pr71973-2.C
===================================================================
--- gcc/testsuite/g++.dg/pr71973-2.C	(revision 0)
+++ gcc/testsuite/g++.dg/pr71973-2.C	(working copy)
@@ -0,0 +1,18 @@
+// { dg-do compile }
+// { dg-options "-Wall -fdump-tree-eh" }
+
+typedef __SIZE_TYPE__ size_t;
+struct tm;
+
+extern "C"
+size_t strftime (char*, size_t, const char*, const struct tm*)
+__attribute__ ((__nothrow__));
+
+void foo () throw ()
+{
+  strftime (0,0,0,0); // { dg-warning "null argument where non-null required" }
+  // { dg-warning "too many arguments for format" "" { target *-*-* } .-1 }
+}
+
+// { dg-final { scan-tree-dump-not "eh_dispatch" "eh" } }
+// { dg-final { scan-tree-dump-not "resx" "eh" } }
Index: gcc/testsuite/g++.dg/pr71973-3.C
===================================================================
--- gcc/testsuite/g++.dg/pr71973-3.C	(revision 0)
+++ gcc/testsuite/g++.dg/pr71973-3.C	(working copy)
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-Wall -fdump-tree-eh" }
+
+extern "C"
+int execve (const char *__path, char *const __argv[], char *const __envp[])
+__attribute__ ((__nothrow__));
+
+void foo () throw ()
+{
+  execve (0,0,0);
+}
+
+// { dg-final { scan-tree-dump-not "eh_dispatch" "eh" } }
+// { dg-final { scan-tree-dump-not "resx" "eh" } }
Index: gcc/tree-core.h
===================================================================
--- gcc/tree-core.h	(revision 241271)
+++ gcc/tree-core.h	(working copy)
@@ -615,6 +615,7 @@ enum tree_index {
   TI_VA_LIST_FPR_COUNTER_FIELD,
   TI_BOOLEAN_TYPE,
   TI_FILEPTR_TYPE,
+  TI_CONST_TM_PTR_TYPE,
   TI_POINTER_SIZED_TYPE,
 
   TI_POINTER_BOUNDS_TYPE,
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 241271)
+++ gcc/tree.c	(working copy)
@@ -6006,6 +6006,7 @@ free_lang_data (void)
   /* Create gimple variants for common types.  */
   ptrdiff_type_node = integer_type_node;
   fileptr_type_node = ptr_type_node;
+  const_tm_ptr_type_node = const_ptr_type_node;
 
   /* Reset some langhooks.  Do not reset types_compatible_p, it may
      still be used indirectly via the get_alias_set langhook.  */
@@ -10310,6 +10311,7 @@ build_common_tree_nodes (bool signed_char)
   const_ptr_type_node
     = build_pointer_type (build_type_variant (void_type_node, 1, 0));
   fileptr_type_node = ptr_type_node;
+  const_tm_ptr_type_node = const_ptr_type_node;
 
   pointer_sized_int_node = build_nonstandard_integer_type (POINTER_SIZE, 1);
 
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 241271)
+++ gcc/tree.h	(working copy)
@@ -3667,6 +3667,8 @@ tree_operand_check_code (const_tree __t, enum tree
 #define va_list_fpr_counter_field	global_trees[TI_VA_LIST_FPR_COUNTER_FIELD]
 /* The C type `FILE *'.  */
 #define fileptr_type_node		global_trees[TI_FILEPTR_TYPE]
+/* The C type `const struct tm *'.  */
+#define const_tm_ptr_type_node		global_trees[TI_CONST_TM_PTR_TYPE]
 #define pointer_sized_int_node		global_trees[TI_POINTER_SIZED_TYPE]
 
 #define boolean_type_node		global_trees[TI_BOOLEAN_TYPE]

Reply via email to