diff mbox

[C++] Warn on redefinition of builtin functions (PR c++/71973)

Message ID AM4PR0701MB21623781CE7CE49B190E86F0E4D00@AM4PR0701MB2162.eurprd07.prod.outlook.com
State Superseded
Headers show

Commit Message

Bernd Edlinger Oct. 17, 2016, 7:18 p.m. UTC
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.edlinger@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.edlinger@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.edlinger@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.edlinger@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.edlinger@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.

Comments

Bernd Edlinger Oct. 24, 2016, 1:37 p.m. UTC | #1
Hi!

I'd like to ping for my patch here:
https://gcc.gnu.org/ml/gcc-patches/2016-10/msg01348.html


Thanks
Bernd.

On 10/17/16 21:18, Bernd Edlinger wrote:
> 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.
Bernd Edlinger Nov. 1, 2016, 2:55 p.m. UTC | #2
Ping...

On 10/24/16 15:36, Bernd Edlinger wrote:
> Hi!

>

> I'd like to ping for my patch here:

> https://gcc.gnu.org/ml/gcc-patches/2016-10/msg01348.html

>

>

> Thanks

> Bernd.

>

> On 10/17/16 21:18, Bernd Edlinger wrote:

>> 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.
Jason Merrill Nov. 1, 2016, 3:02 p.m. UTC | #3
On 10/17/2016 03:18 PM, Bernd Edlinger wrote:
> Regarding this hunk:

>

>         /* Whether or not the builtin can throw exceptions has no

>           bearing on this declarator.  */

> -      TREE_NOTHROW (olddecl) = 0;

> +      TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl);

>

> You may ask, why the old code was working most of the time.

> I think, usually, when types_match == true, there happens another

> assignment to TREE_NOTHROW, later in that function around line 2183:

>

>        /* Merge the type qualifiers.  */

>        if (TREE_READONLY (newdecl))

>          TREE_READONLY (olddecl) = 1;

>        if (TREE_THIS_VOLATILE (newdecl))

>          TREE_THIS_VOLATILE (olddecl) = 1;

>        if (TREE_NOTHROW (newdecl))

>          TREE_NOTHROW (olddecl) = 1;

>

> This is in a big "if (types_match)", so I think that explains,

> why the old code did work normally, and why it fails if the

> parameter don't match, but I still have no idea what to say

> in the comment, except that the code should exactly do what

> the comment above says.


I think a better fix would be to add a copy of TREE_NOTHROW to the else 
block of the if (types_match), to go with the existing copies of 
TREE_READONLY and TREE_THIS_VOLATILE.  But yes, duplicate_decls is a mess.

Jason
Jason Merrill Nov. 1, 2016, 3:20 p.m. UTC | #4
On 10/17/2016 03:18 PM, Bernd Edlinger wrote:
> +@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}.


There's no redefinition here (only a redeclaration), so perhaps 
-Wbuiltin-redeclaration-mismatch?

I'm not even sure we need a new warning.  Can we combine this warning 
with the block that currently follows?

>           else if ((DECL_EXTERN_C_P (newdecl)

>                     && DECL_EXTERN_C_P (olddecl))

>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))

>             {

>               /* A near match; override the builtin.  */

>

>               if (TREE_PUBLIC (newdecl))

>                 warning_at (DECL_SOURCE_LOCATION (newdecl), 0,

>                             "new declaration %q#D ambiguates built-in "

>                             "declaration %q#D", newdecl, olddecl);

>               else

>                 warning (OPT_Wshadow,

>                          DECL_BUILT_IN (olddecl)

>                          ? G_("shadowing built-in function %q#D")

>                          : G_("shadowing library function %q#D"), olddecl);

>             }


It seems to me that if we have an extern "C" declaration that doesn't 
match the built-in, we should just warn.

I looked at some of the testcases you mentioned in the bug report, and 
those declarations aren't extern "C", so we shouldn't be warning about 
them.  Does your current patch still warn about those?

Jason
Bernd Edlinger Nov. 1, 2016, 3:25 p.m. UTC | #5
On 11/01/16 16:02, Jason Merrill wrote:
> On 10/17/2016 03:18 PM, Bernd Edlinger wrote:

>> Regarding this hunk:

>>

>>         /* Whether or not the builtin can throw exceptions has no

>>           bearing on this declarator.  */

>> -      TREE_NOTHROW (olddecl) = 0;

>> +      TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl);

>>

>> You may ask, why the old code was working most of the time.

>> I think, usually, when types_match == true, there happens another

>> assignment to TREE_NOTHROW, later in that function around line 2183:

>>

>>        /* Merge the type qualifiers.  */

>>        if (TREE_READONLY (newdecl))

>>          TREE_READONLY (olddecl) = 1;

>>        if (TREE_THIS_VOLATILE (newdecl))

>>          TREE_THIS_VOLATILE (olddecl) = 1;

>>        if (TREE_NOTHROW (newdecl))

>>          TREE_NOTHROW (olddecl) = 1;

>>

>> This is in a big "if (types_match)", so I think that explains,

>> why the old code did work normally, and why it fails if the

>> parameter don't match, but I still have no idea what to say

>> in the comment, except that the code should exactly do what

>> the comment above says.

>

> I think a better fix would be to add a copy of TREE_NOTHROW to the else

> block of the if (types_match), to go with the existing copies of

> TREE_READONLY and TREE_THIS_VOLATILE.  But yes, duplicate_decls is a mess.

>


Possibly, but I am only aware of problems with redeclarations
of builtins functions, TREE_CODE (olddecl) == FUNCTION_DECL
&& DECL_ARTIFICIAL (olddecl), but the "if (types_match)" can
be called for many other types of decls.

So super scary code here....
Bernd Edlinger Nov. 1, 2016, 3:45 p.m. UTC | #6
On 11/01/16 16:20, Jason Merrill wrote:
> On 10/17/2016 03:18 PM, Bernd Edlinger wrote:

>> +@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}.

>

> There's no redefinition here (only a redeclaration), so perhaps

> -Wbuiltin-redeclaration-mismatch?

>


Works for me.  Thanks.

> I'm not even sure we need a new warning.  Can we combine this warning

> with the block that currently follows?

>


After 20 years of not having a warning on that,
an implicitly enabled warning would at least break lots of bogus
test cases.  Of course in C we have an implicitly enabled warning,
so I would like to at least enable the warning on -Wall, thus
-Wshadow is too weak IMO.

>>           else if ((DECL_EXTERN_C_P (newdecl)

>>                     && DECL_EXTERN_C_P (olddecl))

>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))

>>             {

>>               /* A near match; override the builtin.  */

>>

>>               if (TREE_PUBLIC (newdecl))

>>                 warning_at (DECL_SOURCE_LOCATION (newdecl), 0,

>>                             "new declaration %q#D ambiguates built-in "

>>                             "declaration %q#D", newdecl, olddecl);

>>               else

>>                 warning (OPT_Wshadow,

>>                          DECL_BUILT_IN (olddecl)

>>                          ? G_("shadowing built-in function %q#D")

>>                          : G_("shadowing library function %q#D"),

>> olddecl);

>>             }

>

> It seems to me that if we have an extern "C" declaration that doesn't

> match the built-in, we should just warn.

>

> I looked at some of the testcases you mentioned in the bug report, and

> those declarations aren't extern "C", so we shouldn't be warning about

> them.  Does your current patch still warn about those?

>


No.  After looking at the false positives with the previous patch,
I changed my mind about that.

This started because I wanted to add builtin functions for some
special_function_p names.  And I wanted to warn the user if he uses a
name that is recognized by special_function_p, but the parameters
don't match.  Now I think we need to teach special_function_p to
distinguish "C" functions from "C++" functions, which it currently
cannot do, because that knowledge is only in the C++ FE.


Bernd.
Jason Merrill Nov. 1, 2016, 5:11 p.m. UTC | #7
On Tue, Nov 1, 2016 at 11:45 AM, Bernd Edlinger
<bernd.edlinger@hotmail.de> wrote:
> On 11/01/16 16:20, Jason Merrill wrote:

>> On 10/17/2016 03:18 PM, Bernd Edlinger wrote:

>> I'm not even sure we need a new warning.  Can we combine this warning

>> with the block that currently follows?

>

> After 20 years of not having a warning on that,

> an implicitly enabled warning would at least break lots of bogus

> test cases.


Would it, though?  Which test cases still break with the current patch?

> Of course in C we have an implicitly enabled warning,

> so I would like to at least enable the warning on -Wall, thus

> -Wshadow is too weak IMO.


Right.  The -Wshadow warning is for file-local declarations, so that
doesn't apply to your testcase; I was thinking that we should hit the
first (currently unconditional) warning.

>>>           else if ((DECL_EXTERN_C_P (newdecl)

>>>                     && DECL_EXTERN_C_P (olddecl))

>>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))


So I was thinking to drop the "else" and the compparms test.

>>>             {

>>>               /* A near match; override the builtin.  */

>>>

>>>               if (TREE_PUBLIC (newdecl))

>>>                 warning_at (DECL_SOURCE_LOCATION (newdecl), 0,

>>>                             "new declaration %q#D ambiguates built-in "

>>>                             "declaration %q#D", newdecl, olddecl);


So we would hit this warning.  And change the message to remove
"ambiguates", since we're removing the compparms.

> This started because I wanted to add builtin functions for some

> special_function_p names.  And I wanted to warn the user if he uses a

> name that is recognized by special_function_p, but the parameters

> don't match.  Now I think we need to teach special_function_p to

> distinguish "C" functions from "C++" functions, which it currently

> cannot do, because that knowledge is only in the C++ FE.


It could look at DECL_ASSEMBLER_NAME rather than DECL_NAME?

Jason
Bernd Edlinger Nov. 1, 2016, 6:15 p.m. UTC | #8
On 11/01/16 18:11, Jason Merrill wrote:
> On Tue, Nov 1, 2016 at 11:45 AM, Bernd Edlinger

> <bernd.edlinger@hotmail.de> wrote:

>> On 11/01/16 16:20, Jason Merrill wrote:

>>> On 10/17/2016 03:18 PM, Bernd Edlinger wrote:

>>> I'm not even sure we need a new warning.  Can we combine this warning

>>> with the block that currently follows?

>>

>> After 20 years of not having a warning on that,

>> an implicitly enabled warning would at least break lots of bogus

>> test cases.

>

> Would it, though?  Which test cases still break with the current patch?

>


Less than before, but there are still at least a few of them.

I can make a list and send it tomorrow.

>> Of course in C we have an implicitly enabled warning,

>> so I would like to at least enable the warning on -Wall, thus

>> -Wshadow is too weak IMO.

>

> Right.  The -Wshadow warning is for file-local declarations, so that

> doesn't apply to your testcase; I was thinking that we should hit the

> first (currently unconditional) warning.

>

>>>>           else if ((DECL_EXTERN_C_P (newdecl)

>>>>                     && DECL_EXTERN_C_P (olddecl))

>>>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>>>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))

>

> So I was thinking to drop the "else" and the compparms test.

>


Yes.  But then we must somehow avoid:

           else
             /* Discard the old built-in function.  */
             return NULL_TREE;

It maybe easier, just to copy the warning to the DECL_ANTICIPATED case?

>>>>             {

>>>>               /* A near match; override the builtin.  */

>>>>

>>>>               if (TREE_PUBLIC (newdecl))

>>>>                 warning_at (DECL_SOURCE_LOCATION (newdecl), 0,

>>>>                             "new declaration %q#D ambiguates built-in "

>>>>                             "declaration %q#D", newdecl, olddecl);

>

> So we would hit this warning.  And change the message to remove

> "ambiguates", since we're removing the compparms.

>

>> This started because I wanted to add builtin functions for some

>> special_function_p names.  And I wanted to warn the user if he uses a

>> name that is recognized by special_function_p, but the parameters

>> don't match.  Now I think we need to teach special_function_p to

>> distinguish "C" functions from "C++" functions, which it currently

>> cannot do, because that knowledge is only in the C++ FE.

>

> It could look at DECL_ASSEMBLER_NAME rather than DECL_NAME?

>


Yes.  I think previously special_function_p must have used the
DECL_ASSEMBLER_NAME, at least the comments still mention that.

Also for a "C" function there are target specific naming rules,
some prepend an underscore, some don't, and more, especially
W..DOS has special conventions IIRC.

Maybe a language callback would be good to have for this task.
So that special_function_p can easily check if something is a
C++ function, then it is immediately clear that it is not a
special function.



Bernd.
Jason Merrill Nov. 1, 2016, 7:48 p.m. UTC | #9
On Tue, Nov 1, 2016 at 2:15 PM, Bernd Edlinger
<bernd.edlinger@hotmail.de> wrote:
> On 11/01/16 18:11, Jason Merrill wrote:

>> On Tue, Nov 1, 2016 at 11:45 AM, Bernd Edlinger

>> <bernd.edlinger@hotmail.de> wrote:

>>> On 11/01/16 16:20, Jason Merrill wrote:

>>>> On 10/17/2016 03:18 PM, Bernd Edlinger wrote:

>>>> I'm not even sure we need a new warning.  Can we combine this warning

>>>> with the block that currently follows?

>>>

>>> After 20 years of not having a warning on that,

>>> an implicitly enabled warning would at least break lots of bogus

>>> test cases.

>>

>> Would it, though?  Which test cases still break with the current patch?

>

> Less than before, but there are still at least a few of them.

>

> I can make a list and send it tomorrow.

>

>>> Of course in C we have an implicitly enabled warning,

>>> so I would like to at least enable the warning on -Wall, thus

>>> -Wshadow is too weak IMO.

>>

>> Right.  The -Wshadow warning is for file-local declarations, so that

>> doesn't apply to your testcase; I was thinking that we should hit the

>> first (currently unconditional) warning.

>>

>>>>>           else if ((DECL_EXTERN_C_P (newdecl)

>>>>>                     && DECL_EXTERN_C_P (olddecl))

>>>>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>>>>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))

>>

>> So I was thinking to drop the "else" and the compparms test.

>

> Yes.  But then we must somehow avoid:

>

>            else

>              /* Discard the old built-in function.  */

>              return NULL_TREE;

>

> It maybe easier, just to copy the warning to the DECL_ANTICIPATED case?


Or even move it there; removing the existing warning doesn't change
anything in the testsuite, and I'm having trouble imagining how to
trigger it.

Jason
Bernd Edlinger Nov. 1, 2016, 8 p.m. UTC | #10
On 11/01/16 20:48, Jason Merrill wrote:
>>>>>>           else if ((DECL_EXTERN_C_P (newdecl)

>>>>>>                     && DECL_EXTERN_C_P (olddecl))

>>>>>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>>>>>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))

>>>

>>> So I was thinking to drop the "else" and the compparms test.

>>

>> Yes.  But then we must somehow avoid:

>>

>>            else

>>              /* Discard the old built-in function.  */

>>              return NULL_TREE;

>>

>> It maybe easier, just to copy the warning to the DECL_ANTICIPATED case?

>

> Or even move it there; removing the existing warning doesn't change

> anything in the testsuite, and I'm having trouble imagining how to

> trigger it.

>


Nice.  It must be something, which does not anticipate a declaration.

like:

cat test.cc
int __builtin_abort(void*);

g++ -c test.cc
test.cc:1:5: warning: new declaration 'int __builtin_abort(void*)' 
ambiguates built-in declaration 'void __builtin_abort()'
  int __builtin_abort(void*);
      ^~~~~~~~~~~~~~~

Intersting, the warning comes even though I forgot to add the
extern "C".


Bernd.
Jason Merrill Nov. 1, 2016, 9:31 p.m. UTC | #11
On Tue, Nov 1, 2016 at 4:00 PM, Bernd Edlinger
<bernd.edlinger@hotmail.de> wrote:
> On 11/01/16 20:48, Jason Merrill wrote:

>>>>>>>           else if ((DECL_EXTERN_C_P (newdecl)

>>>>>>>                     && DECL_EXTERN_C_P (olddecl))

>>>>>>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>>>>>>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))

>>>>

>>>> So I was thinking to drop the "else" and the compparms test.

>>>

>>> Yes.  But then we must somehow avoid:

>>>

>>>            else

>>>              /* Discard the old built-in function.  */

>>>              return NULL_TREE;


>>> It maybe easier, just to copy the warning to the DECL_ANTICIPATED case?

>>

>> Or even move it there; removing the existing warning doesn't change

>> anything in the testsuite, and I'm having trouble imagining how to

>> trigger it.

>>

>

> Nice.  It must be something, which does not anticipate a declaration.

>

> like:

>

> cat test.cc

> int __builtin_abort(void*);

>

> g++ -c test.cc

> test.cc:1:5: warning: new declaration 'int __builtin_abort(void*)'

> ambiguates built-in declaration 'void __builtin_abort()'

>   int __builtin_abort(void*);

>       ^~~~~~~~~~~~~~~

>

> Intersting, the warning comes even though I forgot to add the

> extern "C".


Looks like anything starting with __builtin is implicitly extern "C"
(set in grokfndecl).

If we remove the DECL_ANTICIPATED check, I see some failures in
builtin* tests due to missing extern "C".  That seems appropriate at
file scope, but I'm not sure it's right for namespace std.

Jason
Bernd Edlinger Nov. 2, 2016, 6:11 a.m. UTC | #12
On 11/01/16 19:15, Bernd Edlinger wrote:
> On 11/01/16 18:11, Jason Merrill wrote:

>> On Tue, Nov 1, 2016 at 11:45 AM, Bernd Edlinger

>> <bernd.edlinger@hotmail.de> wrote:

>>> On 11/01/16 16:20, Jason Merrill wrote:

>>>> On 10/17/2016 03:18 PM, Bernd Edlinger wrote:

>>>> I'm not even sure we need a new warning.  Can we combine this warning

>>>> with the block that currently follows?

>>>

>>> After 20 years of not having a warning on that,

>>> an implicitly enabled warning would at least break lots of bogus

>>> test cases.

>>

>> Would it, though?  Which test cases still break with the current patch?

>>

>

> Less than before, but there are still at least a few of them.

>

> I can make a list and send it tomorrow.

>


FAIL: g++.dg/cpp1y/lambda-generic-udt.C  -std=gnu++14 (test for excess 
errors)
FAIL: g++.dg/cpp1y/lambda-generic-xudt.C  -std=gnu++14 (test for excess 
errors)
FAIL: g++.dg/init/new15.C  -std=c++11 (test for excess errors)
FAIL: g++.dg/init/new15.C  -std=c++14 (test for excess errors)
FAIL: g++.dg/init/new15.C  -std=c++98 (test for excess errors)
FAIL: g++.dg/ipa/inline-1.C  -std=gnu++11 (test for excess errors)
FAIL: g++.dg/ipa/inline-1.C  -std=gnu++14 (test for excess errors)
FAIL: g++.dg/ipa/inline-1.C  -std=gnu++98 (test for excess errors)
FAIL: g++.dg/ipa/inline-2.C  -std=gnu++11 (test for excess errors)
FAIL: g++.dg/ipa/inline-2.C  -std=gnu++14 (test for excess errors)
FAIL: g++.dg/ipa/inline-2.C  -std=gnu++98 (test for excess errors)
FAIL: g++.dg/tc1/dr20.C  -std=c++11 (test for excess errors)
FAIL: g++.dg/tc1/dr20.C  -std=c++14 (test for excess errors)
FAIL: g++.dg/tc1/dr20.C  -std=c++98 (test for excess errors)
FAIL: g++.dg/tree-ssa/inline-1.C  -std=gnu++11 (test for excess errors)
FAIL: g++.dg/tree-ssa/inline-1.C  -std=gnu++14 (test for excess errors)
FAIL: g++.dg/tree-ssa/inline-1.C  -std=gnu++98 (test for excess errors)
FAIL: g++.dg/tree-ssa/inline-2.C  -std=gnu++11 (test for excess errors)
FAIL: g++.dg/tree-ssa/inline-2.C  -std=gnu++14 (test for excess errors)
FAIL: g++.dg/tree-ssa/inline-2.C  -std=gnu++98 (test for excess errors)
FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O0 -flto 
-flto-partition=1to1 -fno-use-linker-plugin
FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O0 -flto 
-flto-partition=none -fuse-linker-plugin
FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O0 -flto 
-fuse-linker-plugin -fno-fat-lto-objects
FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O2 -flto 
-flto-partition=1to1 -fno-use-linker-plugin
FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O2 -flto 
-flto-partition=none -fuse-linker-plugin -fno-fat-lto-objects
FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O2 -flto 
-fuse-linker-plugin
FAIL: g++.dg/lto/pr68811 cp_lto_pr68811_0.o assemble, -O2
FAIL: g++.old-deja/g++.law/except1.C  -std=gnu++11 (test for excess errors)
FAIL: g++.old-deja/g++.law/except1.C  -std=gnu++14 (test for excess errors)
FAIL: g++.old-deja/g++.law/except1.C  -std=gnu++98 (test for excess errors)
FAIL: g++.old-deja/g++.mike/p700.C  -std=gnu++11 (test for excess errors)
FAIL: g++.old-deja/g++.mike/p700.C  -std=gnu++14 (test for excess errors)
FAIL: g++.old-deja/g++.mike/p700.C  -std=gnu++98 (test for excess errors)
FAIL: g++.old-deja/g++.other/builtins10.C  -std=c++11 (test for excess 
errors)
FAIL: g++.old-deja/g++.other/builtins10.C  -std=c++14 (test for excess 
errors)
FAIL: g++.old-deja/g++.other/realloc.C  -std=c++11 (test for excess errors)
FAIL: g++.old-deja/g++.other/realloc.C  -std=c++14 (test for excess errors)
FAIL: g++.old-deja/g++.other/realloc.C  -std=c++98 (test for excess errors)
FAIL: g++.old-deja/g++.other/vbase5.C  -std=c++11 (test for excess errors)
FAIL: g++.old-deja/g++.other/vbase5.C  -std=c++14 (test for excess errors)
FAIL: g++.old-deja/g++.other/vbase5.C  -std=c++98 (test for excess errors)


The lto test case does emit the warning when assembling, but
it still produces an executable and even executes it.

Also g++.dg/cpp1y/lambda-generic-udt.C, g++.dg/tc1/dr20.C
and g++.old-deja/g++.other/vbase5.C are execution tests.

So I was wrong to assume these were all compile-only tests.

I think that list should be fixable, if we decide to enable
the warning by default.

>>> Of course in C we have an implicitly enabled warning,

>>> so I would like to at least enable the warning on -Wall, thus

>>> -Wshadow is too weak IMO.

>>

>> Right.  The -Wshadow warning is for file-local declarations, so that

>> doesn't apply to your testcase; I was thinking that we should hit the

>> first (currently unconditional) warning.

>>

>>>>>           else if ((DECL_EXTERN_C_P (newdecl)

>>>>>                     && DECL_EXTERN_C_P (olddecl))

>>>>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>>>>                                  TYPE_ARG_TYPES (TREE_TYPE

>>>>> (olddecl))))

>>

>> So I was thinking to drop the "else" and the compparms test.

>>

>

> Yes.  But then we must somehow avoid:

>

>           else

>             /* Discard the old built-in function.  */

>             return NULL_TREE;

>

> It maybe easier, just to copy the warning to the DECL_ANTICIPATED case?

>

>>>>>             {

>>>>>               /* A near match; override the builtin.  */

>>>>>

>>>>>               if (TREE_PUBLIC (newdecl))

>>>>>                 warning_at (DECL_SOURCE_LOCATION (newdecl), 0,

>>>>>                             "new declaration %q#D ambiguates

>>>>> built-in "

>>>>>                             "declaration %q#D", newdecl, olddecl);

>>

>> So we would hit this warning.  And change the message to remove

>> "ambiguates", since we're removing the compparms.

>>

>>> This started because I wanted to add builtin functions for some

>>> special_function_p names.  And I wanted to warn the user if he uses a

>>> name that is recognized by special_function_p, but the parameters

>>> don't match.  Now I think we need to teach special_function_p to

>>> distinguish "C" functions from "C++" functions, which it currently

>>> cannot do, because that knowledge is only in the C++ FE.

>>

>> It could look at DECL_ASSEMBLER_NAME rather than DECL_NAME?

>>

>

> Yes.  I think previously special_function_p must have used the

> DECL_ASSEMBLER_NAME, at least the comments still mention that.

>

> Also for a "C" function there are target specific naming rules,

> some prepend an underscore, some don't, and more, especially

> W..DOS has special conventions IIRC.

>

> Maybe a language callback would be good to have for this task.

> So that special_function_p can easily check if something is a

> C++ function, then it is immediately clear that it is not a

> special function.

>

>

>

> Bernd.
Bernd Edlinger Nov. 2, 2016, 6:36 a.m. UTC | #13
On 11/02/16 07:11, Bernd Edlinger wrote:
> On 11/01/16 19:15, Bernd Edlinger wrote:

>> On 11/01/16 18:11, Jason Merrill wrote:

>>> On Tue, Nov 1, 2016 at 11:45 AM, Bernd Edlinger

>>> <bernd.edlinger@hotmail.de> wrote:

>>>> On 11/01/16 16:20, Jason Merrill wrote:

>>>>> On 10/17/2016 03:18 PM, Bernd Edlinger wrote:

>>>>> I'm not even sure we need a new warning.  Can we combine this warning

>>>>> with the block that currently follows?

>>>>

>>>> After 20 years of not having a warning on that,

>>>> an implicitly enabled warning would at least break lots of bogus

>>>> test cases.

>>>

>>> Would it, though?  Which test cases still break with the current patch?

>>>

>>

>> Less than before, but there are still at least a few of them.

>>

>> I can make a list and send it tomorrow.

>>

>

> FAIL: g++.dg/cpp1y/lambda-generic-udt.C  -std=gnu++14 (test for excess

> errors)

> FAIL: g++.dg/cpp1y/lambda-generic-xudt.C  -std=gnu++14 (test for excess

> errors)

> FAIL: g++.dg/init/new15.C  -std=c++11 (test for excess errors)

> FAIL: g++.dg/init/new15.C  -std=c++14 (test for excess errors)

> FAIL: g++.dg/init/new15.C  -std=c++98 (test for excess errors)

> FAIL: g++.dg/ipa/inline-1.C  -std=gnu++11 (test for excess errors)

> FAIL: g++.dg/ipa/inline-1.C  -std=gnu++14 (test for excess errors)

> FAIL: g++.dg/ipa/inline-1.C  -std=gnu++98 (test for excess errors)

> FAIL: g++.dg/ipa/inline-2.C  -std=gnu++11 (test for excess errors)

> FAIL: g++.dg/ipa/inline-2.C  -std=gnu++14 (test for excess errors)

> FAIL: g++.dg/ipa/inline-2.C  -std=gnu++98 (test for excess errors)

> FAIL: g++.dg/tc1/dr20.C  -std=c++11 (test for excess errors)

> FAIL: g++.dg/tc1/dr20.C  -std=c++14 (test for excess errors)

> FAIL: g++.dg/tc1/dr20.C  -std=c++98 (test for excess errors)

> FAIL: g++.dg/tree-ssa/inline-1.C  -std=gnu++11 (test for excess errors)

> FAIL: g++.dg/tree-ssa/inline-1.C  -std=gnu++14 (test for excess errors)

> FAIL: g++.dg/tree-ssa/inline-1.C  -std=gnu++98 (test for excess errors)

> FAIL: g++.dg/tree-ssa/inline-2.C  -std=gnu++11 (test for excess errors)

> FAIL: g++.dg/tree-ssa/inline-2.C  -std=gnu++14 (test for excess errors)

> FAIL: g++.dg/tree-ssa/inline-2.C  -std=gnu++98 (test for excess errors)

> FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O0 -flto

> -flto-partition=1to1 -fno-use-linker-plugin

> FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O0 -flto

> -flto-partition=none -fuse-linker-plugin

> FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O0 -flto

> -fuse-linker-plugin -fno-fat-lto-objects

> FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O2 -flto

> -flto-partition=1to1 -fno-use-linker-plugin

> FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O2 -flto

> -flto-partition=none -fuse-linker-plugin -fno-fat-lto-objects

> FAIL: g++.dg/lto/20080908-1 cp_lto_20080908-1_0.o assemble, -O2 -flto

> -fuse-linker-plugin

> FAIL: g++.dg/lto/pr68811 cp_lto_pr68811_0.o assemble, -O2

> FAIL: g++.old-deja/g++.law/except1.C  -std=gnu++11 (test for excess errors)

> FAIL: g++.old-deja/g++.law/except1.C  -std=gnu++14 (test for excess errors)

> FAIL: g++.old-deja/g++.law/except1.C  -std=gnu++98 (test for excess errors)

> FAIL: g++.old-deja/g++.mike/p700.C  -std=gnu++11 (test for excess errors)

> FAIL: g++.old-deja/g++.mike/p700.C  -std=gnu++14 (test for excess errors)

> FAIL: g++.old-deja/g++.mike/p700.C  -std=gnu++98 (test for excess errors)

> FAIL: g++.old-deja/g++.other/builtins10.C  -std=c++11 (test for excess

> errors)

> FAIL: g++.old-deja/g++.other/builtins10.C  -std=c++14 (test for excess

> errors)

> FAIL: g++.old-deja/g++.other/realloc.C  -std=c++11 (test for excess errors)

> FAIL: g++.old-deja/g++.other/realloc.C  -std=c++14 (test for excess errors)

> FAIL: g++.old-deja/g++.other/realloc.C  -std=c++98 (test for excess errors)

> FAIL: g++.old-deja/g++.other/vbase5.C  -std=c++11 (test for excess errors)

> FAIL: g++.old-deja/g++.other/vbase5.C  -std=c++14 (test for excess errors)

> FAIL: g++.old-deja/g++.other/vbase5.C  -std=c++98 (test for excess errors)

>

>

> The lto test case does emit the warning when assembling, but

> it still produces an executable and even executes it.

>

> Also g++.dg/cpp1y/lambda-generic-udt.C, g++.dg/tc1/dr20.C

> and g++.old-deja/g++.other/vbase5.C are execution tests.

>

> So I was wrong to assume these were all compile-only tests.

>

> I think that list should be fixable, if we decide to enable

> the warning by default.

>


Aehm, sorry.  I forgot to look at other languages...

                 === obj-c++ tests ===


Running target unix
FAIL: obj-c++.dg/lto/trivial-1 obj_cpp_lto_trivial-1_0.o assemble, -O0 
-flto -fg
nu-runtime
FAIL: obj-c++.dg/lto/trivial-1 obj_cpp_lto_trivial-1_0.o assemble, -O2 
-flto -fg
nu-runtime
FAIL: obj-c++.dg/lto/trivial-1 obj_cpp_lto_trivial-1_0.o assemble, -O0 
-flto -fl
to-partition=none -fgnu-runtime
FAIL: obj-c++.dg/lto/trivial-1 obj_cpp_lto_trivial-1_0.o assemble, -O2 
-flto -fl
to-partition=none -fgnu-runtime

                 === libitm tests ===


Running target unix
FAIL: libitm.c++/dropref.C (test for excess errors)
FAIL: libitm.c++/throwdown.C (test for excess errors)


Bernd.
Bernd Edlinger Nov. 2, 2016, 6:53 a.m. UTC | #14
On 11/01/16 22:31, Jason Merrill wrote:
> On Tue, Nov 1, 2016 at 4:00 PM, Bernd Edlinger

> <bernd.edlinger@hotmail.de> wrote:

>> On 11/01/16 20:48, Jason Merrill wrote:

>>>>>>>>           else if ((DECL_EXTERN_C_P (newdecl)

>>>>>>>>                     && DECL_EXTERN_C_P (olddecl))

>>>>>>>>                    || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),

>>>>>>>>                                  TYPE_ARG_TYPES (TREE_TYPE (olddecl))))

>>>>>

>>>>> So I was thinking to drop the "else" and the compparms test.

>>>>

>>>> Yes.  But then we must somehow avoid:

>>>>

>>>>            else

>>>>              /* Discard the old built-in function.  */

>>>>              return NULL_TREE;

>

>>>> It maybe easier, just to copy the warning to the DECL_ANTICIPATED case?

>>>

>>> Or even move it there; removing the existing warning doesn't change

>>> anything in the testsuite, and I'm having trouble imagining how to

>>> trigger it.

>>>

>>

>> Nice.  It must be something, which does not anticipate a declaration.

>>

>> like:

>>

>> cat test.cc

>> int __builtin_abort(void*);

>>

>> g++ -c test.cc

>> test.cc:1:5: warning: new declaration 'int __builtin_abort(void*)'

>> ambiguates built-in declaration 'void __builtin_abort()'

>>   int __builtin_abort(void*);

>>       ^~~~~~~~~~~~~~~

>>

>> Intersting, the warning comes even though I forgot to add the

>> extern "C".

>

> Looks like anything starting with __builtin is implicitly extern "C"

> (set in grokfndecl).

>


Oh, Well.

we do also have such builtins that begin with __sync_
like

extern "C"
unsigned char __sync_fetch_and_add_1(volatile void*, unsigned char);

> If we remove the DECL_ANTICIPATED check, I see some failures in

> builtin* tests due to missing extern "C".  That seems appropriate at

> file scope, but I'm not sure it's right for namespace std.

>



Interesting, what have you done?

Sounds a bit like the issue I had with the std::abs overloads.

To get rid of that I added this in the DECL_ANTICIPATED path:

+             /* 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;
+


Bernd.
diff mbox

Patch

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]