diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-10-02 10:53:35 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2024-10-02 10:53:35 +0200 |
commit | 5943a2fa1bc5407332a91976c145446cdb8ded7b (patch) | |
tree | d86a1a80f6d73c57efd2da5d1b91d56f2075da84 /gcc | |
parent | ba53ccad554bb4f3c2b0e457a18557ae0f54b05e (diff) | |
download | gcc-5943a2fa1bc5407332a91976c145446cdb8ded7b.zip gcc-5943a2fa1bc5407332a91976c145446cdb8ded7b.tar.gz gcc-5943a2fa1bc5407332a91976c145446cdb8ded7b.tar.bz2 |
libcpp: Implement clang -Wheader-guard warning [PR96842]
The following patch implements the clang -Wheader-guard warning, which warns
if a valid multiple inclusion header guard's #ifndef/#if !defined directive
is immediately (no other non-line directives nor other (non-comment)
tokens in between) followed by #define directive for some different macro,
which in get_suggestion rules is close enough to the actual header guard
macro (i.e. likely misspelling), the #define is object-like with empty
definition (I've followed what clang implements) and the macro isn't defined
later on (at least not on the final #endif at the end of a header).
In this case it emits a warning, so that
#ifndef STDIO_H
#define STDOI_H
...
#endif
or similar misspellings can be caught.
clang enables this warning by default, but I've put it into -Wall instead
as it still seems to be a style warning, nothing more severe; if a header
doesn't survive multiple inclusion because of the misspelling, users will
get different diagnostics.
2024-10-02 Jakub Jelinek <jakub@redhat.com>
PR preprocessor/96842
libcpp/
* include/cpplib.h (struct cpp_options): Add warn_header_guard member.
(enum cpp_warning_reason): Add CPP_W_HEADER_GUARD enumerator.
* internal.h (struct cpp_reader): Add mi_def_cmacro, mi_loc and
mi_def_loc members.
(_cpp_defined_macro_p): Constify type pointed by argument type.
Formatting fix.
* init.cc (cpp_create_reader): Clear
CPP_OPTION (pfile, warn_header_guard).
* directives.cc (struct if_stack): Add def_loc and mi_def_cmacro
members.
(DIRECTIVE_TABLE): Add IF_COND flag to define.
(do_define): Set ifs->mi_def_cmacro on a define immediately following
#ifndef directive for the guard. Clear pfile->mi_valid. Formatting
fix.
(do_endif): Copy over pfile->mi_def_cmacro and pfile->mi_def_loc
if ifs->mi_def_cmacro is set and pfile->mi_cmacro isn't a defined
macro.
(push_conditional): Clear mi_def_cmacro and mi_def_loc members.
* files.cc (_cpp_pop_file_buffer): Emit -Wheader-guard diagnostics.
gcc/
* doc/invoke.texi (Wheader-guard): Document.
gcc/c-family/
* c.opt (Wheader-guard): New option.
* c.opt.urls: Regenerated.
* c-ppoutput.cc (init_pp_output): Initialize also cb->get_suggestion.
gcc/testsuite/
* c-c++-common/cpp/Wheader-guard-1.c: New test.
* c-c++-common/cpp/Wheader-guard-1-1.h: New test.
* c-c++-common/cpp/Wheader-guard-1-2.h: New test.
* c-c++-common/cpp/Wheader-guard-1-3.h: New test.
* c-c++-common/cpp/Wheader-guard-1-4.h: New test.
* c-c++-common/cpp/Wheader-guard-1-5.h: New test.
* c-c++-common/cpp/Wheader-guard-1-6.h: New test.
* c-c++-common/cpp/Wheader-guard-1-7.h: New test.
* c-c++-common/cpp/Wheader-guard-1-8.h: New test.
* c-c++-common/cpp/Wheader-guard-1-9.h: New test.
* c-c++-common/cpp/Wheader-guard-1-10.h: New test.
* c-c++-common/cpp/Wheader-guard-1-11.h: New test.
* c-c++-common/cpp/Wheader-guard-1-12.h: New test.
* c-c++-common/cpp/Wheader-guard-2.c: New test.
* c-c++-common/cpp/Wheader-guard-2.h: New test.
* c-c++-common/cpp/Wheader-guard-3.c: New test.
* c-c++-common/cpp/Wheader-guard-3.h: New test.
Diffstat (limited to 'gcc')
21 files changed, 127 insertions, 1 deletions
diff --git a/gcc/c-family/c-ppoutput.cc b/gcc/c-family/c-ppoutput.cc index c674610..e3f5ca3 100644 --- a/gcc/c-family/c-ppoutput.cc +++ b/gcc/c-family/c-ppoutput.cc @@ -164,6 +164,7 @@ init_pp_output (FILE *out_stream) cb->has_builtin = c_common_has_builtin; cb->has_feature = c_common_has_feature; cb->get_source_date_epoch = cb_get_source_date_epoch; + cb->get_suggestion = cb_get_suggestion; cb->remap_filename = remap_macro_filename; /* Initialize the print structure. */ diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index b598309..77fe1b0 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -828,6 +828,10 @@ Wglobal-module C++ ObjC++ Var(warn_global_module) Warning Init(1) Warn about the global module fragment not containing only preprocessing directives. +Wheader-guard +C ObjC C++ ObjC++ CPP(warn_header_guard) CppReason(CPP_W_HEADER_GUARD) Var(cpp_warn_header_guard) Init(0) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) +Warn when #ifndef of a header guard is followed by #define of a different macro with the header guard macro not defined at the end of header. + Wif-not-aligned C ObjC C++ ObjC++ Var(warn_if_not_aligned) Init(1) Warning Warn when the field in a struct is not aligned. diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls index 47a5492..4cd9a75 100644 --- a/gcc/c-family/c.opt.urls +++ b/gcc/c-family/c.opt.urls @@ -415,6 +415,9 @@ UrlSuffix(gcc/Warning-Options.html#index-Wframe-address) Wglobal-module UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wglobal-module) +Wheader-guard +UrlSuffix(gcc/Warning-Options.html#index-Wheader-guard) + Wif-not-aligned UrlSuffix(gcc/Warning-Options.html#index-Wif-not-aligned) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index bd1208a..e199522 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -372,7 +372,7 @@ Objective-C and Objective-C++ Dialects}. -Wformat-security -Wformat-signedness -Wformat-truncation=@var{n} -Wformat-y2k -Wframe-address -Wframe-larger-than=@var{byte-size} -Wno-free-nonheap-object --Wno-if-not-aligned -Wno-ignored-attributes +-Wheader-guard -Wno-if-not-aligned -Wno-ignored-attributes -Wignored-qualifiers -Wno-incompatible-pointer-types -Whardened -Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n} -Wno-implicit-function-declaration -Wno-implicit-int @@ -10115,6 +10115,19 @@ Do not warn if certain built-in macros are redefined. This suppresses warnings for redefinition of @code{__TIMESTAMP__}, @code{__TIME__}, @code{__DATE__}, @code{__FILE__}, and @code{__BASE_FILE__}. +@opindex Wheader-guard +@item -Wheader-guard +Warn if a valid preprocessor header multiple inclusion guard has +a @code{#define} directive right after @code{#ifndef} or @code{#if !defined} +directive for the multiple inclusion guard, which defines a different macro +from the guard macro with a similar name, the actual multiple inclusion guard +macro isn't defined at the corresponding @code{#ifndef} directive at the end +of the header, and the @code{#define} directive defines an object-like macro +with empty definition. In such case, it often is just a misspelled guard +name, either in the @code{#ifndef} or @code{#if !defined} directive or in the +subsequent @code{#define} directive. This warning is enabled +by @option{-Wall}. + @opindex Wstrict-prototypes @opindex Wno-strict-prototypes @item -Wstrict-prototypes @r{(C and Objective-C only)} diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-1.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-1.h new file mode 100644 index 0000000..1ac3fe8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-1.h @@ -0,0 +1,5 @@ +#ifndef WHEADER_GUARD_1 +#define WHEADER_GUARD_1 +/* This is what header guards should look like. */ +#define SOMETHING1 123 +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-10.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-10.h new file mode 100644 index 0000000..119a2a8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-10.h @@ -0,0 +1,5 @@ +#ifndef WHEADER_GUARD_10 +#define WHEADERGUARD10 +/* Don't warn if it actually isn't a valid header guard. */ +#else +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-11.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-11.h new file mode 100644 index 0000000..88820a5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-11.h @@ -0,0 +1,5 @@ +#ifndef WHEADER_GUARD_11 +#define WHEADERGUARD11 +/* Don't warn if it actually isn't a valid header guard. */ +#elif 1 +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-12.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-12.h new file mode 100644 index 0000000..9233fbf --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-12.h @@ -0,0 +1,5 @@ +#ifndef WHEADER_GUARD_12 +#define WHEADERGUARD12 +/* Don't warn if it actually isn't a valid header guard. */ +#endif +#define ASOMETHING12 diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-2.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-2.h new file mode 100644 index 0000000..25d4fb5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-2.h @@ -0,0 +1,4 @@ +#ifndef WHEADER_GUARD_2 +#define WHEADERGUARD2 1 +/* Don't warn if the different macro defines some tokens. */ +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-3.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-3.h new file mode 100644 index 0000000..d995e3f --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-3.h @@ -0,0 +1,4 @@ +#ifndef WHEADER_GUARD_3 +#define WHEADERGUARD3() +/* Won't warn if it is a function-like macro. */ +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-4.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-4.h new file mode 100644 index 0000000..6d031a5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-4.h @@ -0,0 +1,3 @@ +#ifndef WHEADER_GUARD_4 +/* Don't warn if there is no define after #ifndef. */ +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-5.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-5.h new file mode 100644 index 0000000..d691ba9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-5.h @@ -0,0 +1,5 @@ +#ifndef WHEADER_GUARD_5 +int guard5; +#define WHEADERGUARD5 +/* Don't warn if there are tokens in between #ifndef and #define. */ +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-6.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-6.h new file mode 100644 index 0000000..1057162 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-6.h @@ -0,0 +1,8 @@ +#ifndef WHEADER_GUARD_6 +#define WHEADERGUARD6 +/* Don't warn if WHEADER_GUARD_6 is eventually defined later. */ +#if 0 +#else +#define WHEADER_GUARD_6 +#endif +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-7.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-7.h new file mode 100644 index 0000000..d0e0708 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-7.h @@ -0,0 +1,4 @@ +#ifndef WHEADER_GUARD_7 +#define SOMETHING7 +/* Don't warn if the two macros don't have similar names. */ +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-8.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-8.h new file mode 100644 index 0000000..2be231b --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-8.h @@ -0,0 +1,5 @@ +#ifndef WHEADER_GUARD_8 +#define WHEADERGUARD8 +/* Don't warn if the guard macro is already defined before + including the header. */ +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-9.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-9.h new file mode 100644 index 0000000..2152eaf --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-9.h @@ -0,0 +1,5 @@ +int guard9; +#ifndef WHEADER_GUARD_9 +#define WHEADERGUARD9 +/* Don't warn if it actually isn't a valid header guard. */ +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1.c b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1.c new file mode 100644 index 0000000..6074d87 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-1.c @@ -0,0 +1,19 @@ +/* PR preprocessor/96842 */ +/* { dg-do preprocess } */ +/* { dg-options "-Wall" } */ + +#include "Wheader-guard-1-1.h" +#include "Wheader-guard-1-2.h" +#include "Wheader-guard-1-3.h" +#include "Wheader-guard-1-4.h" +#include "Wheader-guard-1-5.h" +#include "Wheader-guard-1-6.h" +#include "Wheader-guard-1-7.h" +#define WHEADER_GUARD_8 +#include "Wheader-guard-1-8.h" +#include "Wheader-guard-1-9.h" +#include "Wheader-guard-1-10.h" +#include "Wheader-guard-1-11.h" +#include "Wheader-guard-1-12.h" + +int i; diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.c b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.c new file mode 100644 index 0000000..9596fe7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.c @@ -0,0 +1,10 @@ +/* PR preprocessor/96842 */ +/* { dg-do preprocess } */ +/* { dg-options "-Wheader-guard" } */ + +#include "Wheader-guard-2.h" + +int i; + +/* { dg-warning "header guard \"WHEADER_GUARD_2\" followed by \"#define\" of a different macro" "" { target *-*-* } 0 } */ +/* { dg-message "\"WHEADERGUARD2\" is defined here; did you mean \"WHEADER_GUARD_2\"\\\?" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.h new file mode 100644 index 0000000..c38d2d5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.h @@ -0,0 +1,4 @@ +#ifndef WHEADER_GUARD_2 +#define WHEADERGUARD2 +#define SOMETHING2 123 +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.c b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.c new file mode 100644 index 0000000..9fa4fbf --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.c @@ -0,0 +1,10 @@ +/* PR preprocessor/96842 */ +/* { dg-do preprocess } */ +/* { dg-options "-Wall" } */ + +#include "Wheader-guard-3.h" + +int i; + +/* { dg-warning "header guard \"WHEADER_GUARD_3\" followed by \"#define\" of a different macro" "" { target *-*-* } 0 } */ +/* { dg-message "\"WHEADERGUARD3\" is defined here; did you mean \"WHEADER_GUARD_3\"\\\?" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.h b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.h new file mode 100644 index 0000000..cb610ed --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.h @@ -0,0 +1,4 @@ +#if !defined(WHEADER_GUARD_3) +#define WHEADERGUARD3 +#define SOMETHING3 123 +#endif |