mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-21 19:35:28 -05:00
c++, c: Introduce -Wkeyword-macro warning/pedwarn - part of C++26 P2843R3 [PR120778]
The following patch introduces a -Wkeyword-macro warning that clang has since 2014 to implement part of C++26 P2843R3 Preprocessing is never undefined paper. The relevant change in the paper is moving [macro.names]/2 paragraph to https://eel.is/c++draft/cpp.replace.general#9 : "A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 4, or to the attribute-tokens described in [dcl.attr], except that the names likely and unlikely may be defined as function-like macros." Now, my understanding of the paper is that in [macro.names] and surrounding sections the word shall bears different meaning from [cpp.replace.general], where only the latter location implies ill-formed, diagnostic required. The warning in clang when introduced diagnosed all #define/#undef directives on keywords, but shortly after introduction has been changed not to diagnose #undef at all (with "#undef a keyword is generally harmless but used often in configuration scripts" message) and later on even the #define part tweaked - not warn about say #define inline (or const, extern, static), or #define keyword keyword or #define keyword __keyword or #define keyword __keyword__ Later on the warning has been moved to be only pedantic diagnostic unless requested by users. Clearly some code in the wild does e.g. #define private public and similar games, or e.g. Linux kernel (sure, C) does #define inline __inline__ __attribute__((__always_inline__)) etc. Now, I believe at least with the current C++26 wording such exceptions aren't allowed (unless it is changed to IFNDR). But given that this is just pedantic stuff, the following patch makes the warning off by default for C and C++ before C++26 and even for C++26 it enables it by default only if -pedantic/-pedantic-errors (in that case it pedwarns, otherwise it warns). And it diagnoses both #define and #undef without exceptions. From what I can see, all the current NODE_WARN cases are macros starting with __ with one exception (_Pragma). As the NODE_* flags seem to be a limited resource, I chose to just use NODE_WARN as well and differentiate on the node names (if they don't start with __ or _P, they are considered to be -Wkeyword-macro registered ones, otherwise old NODE_WARN cases, typically builtin macros or __STDC* macros). 2025-08-07 Jakub Jelinek <jakub@redhat.com> PR preprocessor/120778 gcc/ * doc/invoke.texi (Wkeyword-macro): Document. gcc/c-family/ * c.opt (Wkeyword-macro): New option. * c.opt.urls: Regenerate. * c-common.h (cxx_dialect): Comment formatting fix. * c-opts.cc (c_common_post_options): Default to -Wkeyword-macro for C++26 if pedantic. gcc/c/ * c-decl.cc (c_init_decl_processing): Mark cpp nodes corresponding to keywords as NODE_WARN if warn_keyword_macro. gcc/cp/ * lex.cc (cxx_init): Mark cpp nodes corresponding to keywords, identifiers with special meaning and standard attribute identifiers as NODE_WARN if warn_keyword_macro. gcc/testsuite/ * gcc.dg/Wkeyword-macro-1.c: New test. * gcc.dg/Wkeyword-macro-2.c: New test. * gcc.dg/Wkeyword-macro-3.c: New test. * gcc.dg/Wkeyword-macro-4.c: New test. * gcc.dg/Wkeyword-macro-5.c: New test. * gcc.dg/Wkeyword-macro-6.c: New test. * gcc.dg/Wkeyword-macro-7.c: New test. * gcc.dg/Wkeyword-macro-8.c: New test. * gcc.dg/Wkeyword-macro-9.c: New test. * g++.dg/warn/Wkeyword-macro-1.C: New test. * g++.dg/warn/Wkeyword-macro-2.C: New test. * g++.dg/warn/Wkeyword-macro-3.C: New test. * g++.dg/warn/Wkeyword-macro-4.C: New test. * g++.dg/warn/Wkeyword-macro-5.C: New test. * g++.dg/warn/Wkeyword-macro-6.C: New test. * g++.dg/warn/Wkeyword-macro-7.C: New test. * g++.dg/warn/Wkeyword-macro-8.C: New test. * g++.dg/warn/Wkeyword-macro-9.C: New test. * g++.dg/warn/Wkeyword-macro-10.C: New test. * g++.dg/opt/pr82577.C: Don't #define register to nothing for C++17 and later. Instead define reg macro to nothing for C++17 and later or to register and use it instead of register. * g++.dg/modules/atom-preamble-3.C: Add -Wno-keyword-macro to dg-additional-options. * g++.dg/template/sfinae17.C (static_assert): Rename macro to ... (my_static_assert): ... this. (main): Use my_static_assert instead of static_assert. libcpp/ * include/cpplib.h (struct cpp_options): Add cpp_warn_keyword_macro. (enum cpp_warning_reason): Add CPP_W_KEYWORD_MACRO enumerator. (cpp_keyword_p): New inline function. * directives.cc (do_undef): Support -Wkeyword-macro diagnostics. * macro.cc (warn_of_redefinition): Ignore NODE_WARN flag on nodes registered for -Wkeyword-macro. (_cpp_create_definition): Support -Wkeyword-macro diagnostics. Formatting fixes.
This commit is contained in:
committed by
Jakub Jelinek
parent
48787c734e
commit
64859dc6e2
@@ -734,13 +734,30 @@ do_undef (cpp_reader *pfile)
|
||||
if (pfile->cb.undef)
|
||||
pfile->cb.undef (pfile, pfile->directive_line, node);
|
||||
|
||||
/* 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_pedantic)
|
||||
&& CPP_OPTION (pfile, cplusplus)
|
||||
&& CPP_OPTION (pfile, lang) >= CLK_GNUCXX26)
|
||||
cpp_pedwarning (pfile, CPP_W_KEYWORD_MACRO,
|
||||
"undefining keyword %qs", NODE_NAME (node));
|
||||
else
|
||||
cpp_warning (pfile, CPP_W_KEYWORD_MACRO,
|
||||
"undefining keyword %qs", NODE_NAME (node));
|
||||
diagnosed = true;
|
||||
}
|
||||
/* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified
|
||||
identifier is not currently defined as a macro name. */
|
||||
if (cpp_macro_p (node))
|
||||
{
|
||||
if (node->flags & NODE_WARN)
|
||||
cpp_error (pfile, CPP_DL_WARNING,
|
||||
"undefining %qs", NODE_NAME (node));
|
||||
{
|
||||
if (!diagnosed)
|
||||
cpp_error (pfile, CPP_DL_WARNING,
|
||||
"undefining %qs", NODE_NAME (node));
|
||||
}
|
||||
else if (cpp_builtin_macro_p (node)
|
||||
&& CPP_OPTION (pfile, warn_builtin_macro_redefined))
|
||||
cpp_warning (pfile, CPP_W_BUILTIN_MACRO_REDEFINED,
|
||||
|
||||
@@ -620,6 +620,9 @@ struct cpp_options
|
||||
/* True if -finput-charset= option has been used explicitly. */
|
||||
bool cpp_input_charset_explicit;
|
||||
|
||||
/* True if -Wkeyword-macro. */
|
||||
bool cpp_warn_keyword_macro;
|
||||
|
||||
/* -Wleading-whitespace= value. */
|
||||
unsigned char cpp_warn_leading_whitespace;
|
||||
|
||||
@@ -757,7 +760,8 @@ enum cpp_warning_reason {
|
||||
CPP_W_HEADER_GUARD,
|
||||
CPP_W_PRAGMA_ONCE_OUTSIDE_HEADER,
|
||||
CPP_W_LEADING_WHITESPACE,
|
||||
CPP_W_TRAILING_WHITESPACE
|
||||
CPP_W_TRAILING_WHITESPACE,
|
||||
CPP_W_KEYWORD_MACRO
|
||||
};
|
||||
|
||||
/* Callback for header lookup for HEADER, which is the name of a
|
||||
@@ -1250,6 +1254,17 @@ inline bool cpp_fun_like_macro_p (cpp_hashnode *node)
|
||||
return cpp_user_macro_p (node) && node->value.macro->fun_like;
|
||||
}
|
||||
|
||||
/* Return true for nodes marked for -Wkeyword-macro diagnostics. */
|
||||
inline bool cpp_keyword_p (cpp_hashnode *node)
|
||||
{
|
||||
/* As keywords are marked identifiers which don't start with underscore
|
||||
or start with underscore followed by capital letter (except for
|
||||
_Pragma). */
|
||||
return ((node->flags & NODE_WARN)
|
||||
&& (NODE_NAME (node)[0] != '_'
|
||||
|| (NODE_NAME (node)[1] != '_' && NODE_NAME (node)[1] != 'P')));
|
||||
}
|
||||
|
||||
extern const unsigned char *cpp_macro_definition (cpp_reader *, cpp_hashnode *);
|
||||
extern const unsigned char *cpp_macro_definition (cpp_reader *, cpp_hashnode *,
|
||||
const cpp_macro *);
|
||||
|
||||
@@ -3411,7 +3411,11 @@ warn_of_redefinition (cpp_reader *pfile, cpp_hashnode *node,
|
||||
{
|
||||
/* Some redefinitions need to be warned about regardless. */
|
||||
if (node->flags & NODE_WARN)
|
||||
return true;
|
||||
{
|
||||
/* Ignore NODE_WARN on -Wkeyword-macro registered identifiers though. */
|
||||
if (!CPP_OPTION (pfile, cpp_warn_keyword_macro) || !cpp_keyword_p (node))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Suppress warnings for builtins that lack the NODE_WARN flag,
|
||||
unless Wbuiltin-macro-redefined. */
|
||||
@@ -3949,6 +3953,25 @@ _cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node,
|
||||
if (name_loc)
|
||||
macro->line = name_loc;
|
||||
|
||||
/* Handle -Wkeyword-macro registered identifiers. */
|
||||
if (CPP_OPTION (pfile, cpp_warn_keyword_macro) && cpp_keyword_p (node))
|
||||
{
|
||||
if (macro->fun_like
|
||||
&& CPP_OPTION (pfile, cplusplus)
|
||||
&& (strcmp ((const char *) NODE_NAME (node), "likely") == 0
|
||||
|| strcmp ((const char *) NODE_NAME (node), "unlikely") == 0))
|
||||
/* likely and unlikely can be defined as function-like macros. */;
|
||||
else if (CPP_OPTION (pfile, cpp_pedantic)
|
||||
&& CPP_OPTION (pfile, cplusplus)
|
||||
&& CPP_OPTION (pfile, lang) >= CLK_GNUCXX26)
|
||||
cpp_pedwarning_with_line (pfile, CPP_W_KEYWORD_MACRO, macro->line, 0,
|
||||
"keyword %qs defined as macro",
|
||||
NODE_NAME (node));
|
||||
else
|
||||
cpp_warning_with_line (pfile, CPP_W_KEYWORD_MACRO, macro->line, 0,
|
||||
"keyword %qs defined as macro",
|
||||
NODE_NAME (node));
|
||||
}
|
||||
if (cpp_macro_p (node))
|
||||
{
|
||||
if (CPP_OPTION (pfile, warn_unused_macros))
|
||||
@@ -3957,12 +3980,12 @@ _cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node,
|
||||
if (warn_of_redefinition (pfile, node, macro))
|
||||
{
|
||||
const enum cpp_warning_reason reason
|
||||
= (cpp_builtin_macro_p (node) && !(node->flags & NODE_WARN))
|
||||
? CPP_W_BUILTIN_MACRO_REDEFINED : CPP_W_NONE;
|
||||
= (cpp_builtin_macro_p (node) && !(node->flags & NODE_WARN)
|
||||
? CPP_W_BUILTIN_MACRO_REDEFINED : CPP_W_NONE);
|
||||
|
||||
bool warned
|
||||
= cpp_pedwarning_with_line (pfile, reason, macro->line, 0,
|
||||
"%qs redefined", NODE_NAME (node));
|
||||
= cpp_pedwarning_with_line (pfile, reason, macro->line, 0,
|
||||
"%qs redefined", NODE_NAME (node));
|
||||
|
||||
if (warned && cpp_user_macro_p (node))
|
||||
cpp_error_with_line (pfile, CPP_DL_NOTE, node->value.macro->line,
|
||||
|
||||
Reference in New Issue
Block a user