c++: Add -Wno-changes-meaning

In recent years this error has been coming up more because other compilers
don't diagnose it as consistently.  So let's add a flag for it, and be more
lenient about cases that aren't likely to cause bugs.

gcc/ChangeLog:

	* doc/invoke.texi: Document -Wno-changes-meaning.

gcc/c-family/ChangeLog:

	* c.opt: Add -Wno-changes-meaning.

gcc/cp/ChangeLog:

	* class.cc (note_name_declared_in_class): Change from permerror to
	-Wchanges-meaning pedwarn, forcing -pedantic-errors for most cases.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/changes-meaning2.C: New test.
	* g++.dg/warn/changes-meaning3.C: New test.
This commit is contained in:
Jason Merrill 2023-01-31 12:56:56 -05:00
parent d03ae4be2c
commit e2f939d30f
5 changed files with 64 additions and 4 deletions

View file

@ -494,6 +494,10 @@ Wcatch-value=
C++ ObjC++ Var(warn_catch_value) Warning Joined RejectNegative UInteger LangEnabledBy(C++ ObjC++,Wall, 1, 0) IntegerRange(0, 3)
Warn about catch handlers of non-reference type.
Wchanges-meaning
C++ ObjC++ Var(warn_changes_meaning) Warning Init(1)
Complain about a name being declared as a class member after a previous use of the same name.
Wchar-subscripts
C ObjC C++ ObjC++ Var(warn_char_subscripts) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn about subscripts whose type is \"char\".

View file

@ -9016,7 +9016,7 @@ note_name_declared_in_class (tree name, tree decl)
return;
/* The C language allows members to be declared with a type of the same
name, and the C++ standard says this diagnostic is not required. So
allow it in extern "C" blocks unless predantic is specified.
allow it in extern "C" blocks unless pedantic is specified.
Allow it in all cases if -ms-extensions is specified. */
if ((!pedantic && current_lang_name == lang_name_c)
|| flag_ms_extensions)
@ -9032,9 +9032,19 @@ note_name_declared_in_class (tree name, tree decl)
A name N used in a class S shall refer to the same declaration
in its context and when re-evaluated in the completed scope of
S. */
if (permerror (location_of (decl),
"declaration of %q#D changes meaning of %qD",
decl, OVL_NAME (decl)))
auto ov = make_temp_override (global_dc->pedantic_errors);
if (TREE_CODE (decl) == TYPE_DECL
&& TREE_CODE (olddecl) == TYPE_DECL
&& same_type_p (TREE_TYPE (decl), TREE_TYPE (olddecl)))
/* Different declaration, but same meaning; just warn. */;
else if (flag_permissive)
/* Let -fpermissive make it a warning like past versions. */;
else
/* Make it an error. */
global_dc->pedantic_errors = 1;
if (pedwarn (location_of (decl), OPT_Wchanges_meaning,
"declaration of %q#D changes meaning of %qD",
decl, OVL_NAME (decl)))
{
inform (loc, "used here to mean %q#D", olddecl);
inform (location_of (olddecl), "declared here" );

View file

@ -6287,6 +6287,23 @@ union U @{
@end itemize
@item -Wno-changes-meaning @r{(C++ and Objective-C++ only)}
C++ requires that unqualified uses of a name within a class have the
same meaning in the complete scope of the class, so declaring the name
after using it is ill-formed:
@smallexample
struct A;
struct B1 @{ A a; typedef A A; @}; // warning, 'A' changes meaning
struct B2 @{ A a; struct A @{ @}; @}; // error, 'A' changes meaning
@end smallexample
By default, the B1 case is only a warning because the two declarations
have the same type, while the B2 case is an error. Both diagnostics
can be disabled with @option{-Wno-changes-meaning}. Alternately, the
error case can be reduced to a warning with
@option{-Wno-error=changes-meaning} or @option{-fpermissive}.
Both diagnostics are also suppressed by @option{-fms-extensions}.
@item -Wchar-subscripts
@opindex Wchar-subscripts
@opindex Wno-char-subscripts

View file

@ -0,0 +1,16 @@
// It's an error to redeclare a name after using it in the class, but be
// lenient if it has the same meaning.
// { dg-options "" }
struct Lock { };
struct Traits
{
Lock lock;
typedef ::Lock Lock; // { dg-warning -Wchanges-meaning }
};
struct Traits2
{
Lock lock;
typedef int Lock; // { dg-error -Wchanges-meaning }
};

View file

@ -0,0 +1,13 @@
// { dg-additional-options "-Wno-changes-meaning" }
struct Lock { };
struct Traits
{
Lock lock;
typedef ::Lock Lock;
};
struct Traits2
{
Lock lock;
typedef int Lock;
};