aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-10-02 10:53:35 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2024-10-02 10:53:35 +0200
commit5943a2fa1bc5407332a91976c145446cdb8ded7b (patch)
treed86a1a80f6d73c57efd2da5d1b91d56f2075da84 /gcc
parentba53ccad554bb4f3c2b0e457a18557ae0f54b05e (diff)
downloadgcc-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')
-rw-r--r--gcc/c-family/c-ppoutput.cc1
-rw-r--r--gcc/c-family/c.opt4
-rw-r--r--gcc/c-family/c.opt.urls3
-rw-r--r--gcc/doc/invoke.texi15
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-1.h5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-10.h5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-11.h5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-12.h5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-2.h4
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-3.h4
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-4.h3
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-5.h5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-6.h8
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-7.h4
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-8.h5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1-9.h5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-1.c19
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.c10
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-2.h4
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.c10
-rw-r--r--gcc/testsuite/c-c++-common/cpp/Wheader-guard-3.h4
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