c++: Warn on #undef/#define of remaining cpp.predefined macros [PR120778]

We already warn on #undef or pedwarn on #define (but not on #define
after #undef) of some builtin macros mentioned in cpp.predefined.

The C++26 P2843R3 paper changes it from (compile time) undefined behavior
to ill-formed.  The following patch arranges for warning (for #undef)
and pedwarn (on #define) for the remaining cpp.predefined macros.
__cpp_* feature test macros only for C++20 which added some of them
to cpp.predefined, in earlier C++ versions it was just an extension and
for pedantic diagnostic I think we don't need to diagnose anything,
__STDCPP_* and __cplusplus macros for all C++ versions where they appeared.

Like the earlier posted -Wkeyword-macro diagnostics (which is done
regardless whether the identifier is defined as a macro or not, obviously
most likely none of the keywords are defined as macros initially), this
one also warns on #undef when a macro isn't defined or later #define
after #undef.

2025-08-15  Jakub Jelinek  <jakub@redhat.com>

	PR preprocessor/120778
	PR target/121520
gcc/c-family/
	* c-cppbuiltin.cc (c_cpp_builtins): Implement C++26 DR 2581.  Add
	cpp_define_warn lambda and use it as well as cpp_warn where needed.
	In the if (c_dialect_cxx ()) block with __cpp_* predefinitions add
	cpp_define lambda.  Formatting fixes.
gcc/c/
	* c-decl.cc (c_init_decl_processing): Use cpp_warn instead of
	cpp_lookup and NODE_WARN bit setting.
gcc/cp/
	* lex.cc (cxx_init): Remove warn_on lambda.  Use cpp_warn instead of
	cpp_lookup and NODE_WARN bit setting or warn_on.
gcc/testsuite/
	* g++.dg/DRs/dr2581-1.C: New test.
	* g++.dg/DRs/dr2581-2.C: New test.
	* c-c++-common/cpp/pr92296-2.c: Expect warnings also on defining
	special macros after undefining them.
libcpp/
	* include/cpplib.h (struct cpp_options): Add
	suppress_builtin_macro_warnings member.
	(cpp_warn): New inline functions.
	* init.cc (cpp_create_reader): Clear suppress_builtin_macro_warnings.
	(cpp_init_builtins): Call cpp_warn on __cplusplus, __STDC__,
	__STDC_VERSION__, __STDC_MB_MIGHT_NEQ_WC__ and
	__STDCPP_STRICT_POINTER_SAFETY__ when appropriate.
	* directives.cc (do_undef): Warn on undefining NODE_WARN macros if
	not cpp_keyword_p.  Don't emit any NODE_WARN related diagnostics
	if CPP_OPTION (pfile, suppress_builtin_macro_warnings).
	(cpp_define, _cpp_define_builtin, cpp_undef): Temporarily set
	CPP_OPTION (pfile, suppress_builtin_macro_warnings) around
	run_directive calls.
	* macro.cc (_cpp_create_definition): Warn on defining NODE_WARN
	macros if they weren't previously defined and not cpp_keyword_p.
	Ignore NODE_WARN for diagnostics if
	CPP_OPTION (pfile, suppress_builtin_macro_warnings).
This commit is contained in:
Jakub Jelinek
2025-08-15 22:31:27 +02:00
committed by Jakub Jelinek
parent 87f354ca75
commit cdd015c4dd
10 changed files with 357 additions and 47 deletions

View File

@@ -736,7 +736,9 @@ do_undef (cpp_reader *pfile)
/* Handle -Wkeyword-macro registered identifiers. */
bool diagnosed = false;
if (CPP_OPTION (pfile, cpp_warn_keyword_macro) && cpp_keyword_p (node))
if (CPP_OPTION (pfile, cpp_warn_keyword_macro)
&& !CPP_OPTION (pfile, suppress_builtin_macro_warnings)
&& cpp_keyword_p (node))
{
if (CPP_OPTION (pfile, cpp_pedantic)
&& CPP_OPTION (pfile, cplusplus)
@@ -752,7 +754,8 @@ do_undef (cpp_reader *pfile)
identifier is not currently defined as a macro name. */
if (cpp_macro_p (node))
{
if (node->flags & NODE_WARN)
if ((node->flags & NODE_WARN)
&& !CPP_OPTION (pfile, suppress_builtin_macro_warnings))
{
if (!diagnosed)
cpp_error (pfile, CPP_DL_WARNING,
@@ -769,6 +772,11 @@ do_undef (cpp_reader *pfile)
_cpp_free_definition (node);
}
else if ((node->flags & NODE_WARN)
&& !CPP_OPTION (pfile, suppress_builtin_macro_warnings)
&& !diagnosed
&& !cpp_keyword_p (node))
cpp_error (pfile, CPP_DL_WARNING, "undefining %qs", NODE_NAME (node));
}
check_eol (pfile, false);
@@ -3087,7 +3095,9 @@ cpp_define (cpp_reader *pfile, const char *str)
}
buf[count] = '\n';
CPP_OPTION (pfile, suppress_builtin_macro_warnings) = 1;
run_directive (pfile, T_DEFINE, buf, count);
CPP_OPTION (pfile, suppress_builtin_macro_warnings) = 0;
}
/* Like cpp_define, but does not warn about unused macro. */
@@ -3141,7 +3151,9 @@ _cpp_define_builtin (cpp_reader *pfile, const char *str)
char *buf = (char *) alloca (len + 1);
memcpy (buf, str, len);
buf[len] = '\n';
CPP_OPTION (pfile, suppress_builtin_macro_warnings) = 1;
run_directive (pfile, T_DEFINE, buf, len);
CPP_OPTION (pfile, suppress_builtin_macro_warnings) = 0;
}
/* Process MACRO as if it appeared as the body of an #undef. */
@@ -3152,7 +3164,9 @@ cpp_undef (cpp_reader *pfile, const char *macro)
char *buf = (char *) alloca (len + 1);
memcpy (buf, macro, len);
buf[len] = '\n';
CPP_OPTION (pfile, suppress_builtin_macro_warnings) = 1;
run_directive (pfile, T_UNDEF, buf, len);
CPP_OPTION (pfile, suppress_builtin_macro_warnings) = 0;
}
/* Replace a previous definition DEF of the macro STR. If DEF is NULL,

View File

@@ -435,6 +435,10 @@ struct cpp_options
Presumably the usage is protected by the appropriate #ifdef. */
unsigned char warn_variadic_macros;
/* Non-zero means suppress diagnostics for NODE_WARN #define or #undef.
Used for cpp_define/cpp_undef. */
unsigned char suppress_builtin_macro_warnings;
/* Nonzero means warn about builtin macros that are redefined or
explicitly undefined. */
unsigned char warn_builtin_macro_redefined;
@@ -1526,6 +1530,21 @@ extern cpp_comment_table *cpp_get_comments (cpp_reader *);
extern cpp_hashnode *cpp_lookup (cpp_reader *, const unsigned char *,
unsigned int);
/* Set NODE_WARN flag for NAME, such that there will be diagnostics
for #define or #undef of NAME. */
inline void
cpp_warn (cpp_reader *pfile, const char *name, unsigned int len)
{
cpp_lookup (pfile, (const unsigned char *) name, len)->flags |= NODE_WARN;
}
inline void
cpp_warn (cpp_reader *pfile, const char *name)
{
cpp_warn (pfile, name, strlen (name));
}
typedef int (*cpp_cb) (cpp_reader *, cpp_hashnode *, void *);
extern void cpp_forall_identifiers (cpp_reader *, cpp_cb, void *);

View File

@@ -246,6 +246,7 @@ cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
CPP_OPTION (pfile, dollars_in_ident) = 1;
CPP_OPTION (pfile, warn_dollars) = 1;
CPP_OPTION (pfile, warn_variadic_macros) = 1;
CPP_OPTION (pfile, suppress_builtin_macro_warnings) = 0;
CPP_OPTION (pfile, warn_builtin_macro_redefined) = 1;
CPP_OPTION (pfile, cpp_warn_implicit_fallthrough) = 0;
CPP_OPTION (pfile, warn_header_guard) = 0;
@@ -593,6 +594,8 @@ cpp_init_builtins (cpp_reader *pfile, int hosted)
&& (! CPP_OPTION (pfile, stdc_0_in_system_headers)
|| CPP_OPTION (pfile, std)))
_cpp_define_builtin (pfile, "__STDC__ 1");
else if (CPP_OPTION (pfile, cplusplus))
cpp_warn (pfile, "__STDC__");
if (CPP_OPTION (pfile, cplusplus))
{
@@ -618,6 +621,14 @@ cpp_init_builtins (cpp_reader *pfile, int hosted)
_cpp_define_builtin (pfile, "__cplusplus 201103L");
else
_cpp_define_builtin (pfile, "__cplusplus 199711L");
cpp_warn (pfile, "__cplusplus");
if (CPP_OPTION (pfile, lang) >= CLK_GNUCXX11)
{
cpp_warn (pfile, "__STDC_VERSION__");
cpp_warn (pfile, "__STDC_MB_MIGHT_NEQ_WC__");
if (CPP_OPTION (pfile, lang) < CLK_GNUCXX23)
cpp_warn (pfile, "__STDCPP_STRICT_POINTER_SAFETY__");
}
}
else if (CPP_OPTION (pfile, lang) == CLK_ASM)
_cpp_define_builtin (pfile, "__ASSEMBLER__ 1");

View File

@@ -3412,8 +3412,11 @@ warn_of_redefinition (cpp_reader *pfile, cpp_hashnode *node,
/* Some redefinitions need to be warned about regardless. */
if (node->flags & NODE_WARN)
{
/* Ignore NODE_WARN on -Wkeyword-macro registered identifiers though. */
if (!CPP_OPTION (pfile, cpp_warn_keyword_macro) || !cpp_keyword_p (node))
/* Ignore NODE_WARN on -Wkeyword-macro registered identifiers though
or during cpp_define. */
if (!CPP_OPTION (pfile, suppress_builtin_macro_warnings)
&& (!CPP_OPTION (pfile, cpp_warn_keyword_macro)
|| !cpp_keyword_p (node)))
return true;
}
@@ -3954,7 +3957,9 @@ _cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node,
macro->line = name_loc;
/* Handle -Wkeyword-macro registered identifiers. */
if (CPP_OPTION (pfile, cpp_warn_keyword_macro) && cpp_keyword_p (node))
if (CPP_OPTION (pfile, cpp_warn_keyword_macro)
&& !CPP_OPTION (pfile, suppress_builtin_macro_warnings)
&& cpp_keyword_p (node))
{
if (macro->fun_like
&& CPP_OPTION (pfile, cplusplus)
@@ -3994,6 +3999,11 @@ _cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node,
}
_cpp_free_definition (node);
}
else if ((node->flags & NODE_WARN)
&& !CPP_OPTION (pfile, suppress_builtin_macro_warnings)
&& !cpp_keyword_p (node))
cpp_error_with_line (pfile, CPP_DL_WARNING, macro->line, 0,
"%qs defined", NODE_NAME (node));
/* Enter definition in hash table. */
node->type = NT_USER_MACRO;