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. */
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.
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)
-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
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)}
--- /dev/null
+#ifndef WHEADER_GUARD_1
+#define WHEADER_GUARD_1
+/* This is what header guards should look like. */
+#define SOMETHING1 123
+#endif
--- /dev/null
+#ifndef WHEADER_GUARD_10
+#define WHEADERGUARD10
+/* Don't warn if it actually isn't a valid header guard. */
+#else
+#endif
--- /dev/null
+#ifndef WHEADER_GUARD_11
+#define WHEADERGUARD11
+/* Don't warn if it actually isn't a valid header guard. */
+#elif 1
+#endif
--- /dev/null
+#ifndef WHEADER_GUARD_12
+#define WHEADERGUARD12
+/* Don't warn if it actually isn't a valid header guard. */
+#endif
+#define ASOMETHING12
--- /dev/null
+#ifndef WHEADER_GUARD_2
+#define WHEADERGUARD2 1
+/* Don't warn if the different macro defines some tokens. */
+#endif
--- /dev/null
+#ifndef WHEADER_GUARD_3
+#define WHEADERGUARD3()
+/* Won't warn if it is a function-like macro. */
+#endif
--- /dev/null
+#ifndef WHEADER_GUARD_4
+/* Don't warn if there is no define after #ifndef. */
+#endif
--- /dev/null
+#ifndef WHEADER_GUARD_5
+int guard5;
+#define WHEADERGUARD5
+/* Don't warn if there are tokens in between #ifndef and #define. */
+#endif
--- /dev/null
+#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
--- /dev/null
+#ifndef WHEADER_GUARD_7
+#define SOMETHING7
+/* Don't warn if the two macros don't have similar names. */
+#endif
--- /dev/null
+#ifndef WHEADER_GUARD_8
+#define WHEADERGUARD8
+/* Don't warn if the guard macro is already defined before
+ including the header. */
+#endif
--- /dev/null
+int guard9;
+#ifndef WHEADER_GUARD_9
+#define WHEADERGUARD9
+/* Don't warn if it actually isn't a valid header guard. */
+#endif
--- /dev/null
+/* 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;
--- /dev/null
+/* 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 } */
--- /dev/null
+#ifndef WHEADER_GUARD_2
+#define WHEADERGUARD2
+#define SOMETHING2 123
+#endif
--- /dev/null
+/* 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 } */
--- /dev/null
+#if !defined(WHEADER_GUARD_3)
+#define WHEADERGUARD3
+#define SOMETHING3 123
+#endif
{
struct if_stack *next;
location_t line; /* Line where condition started. */
- const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */
+ location_t def_loc; /* Locus of the following #define if any. */
+ const cpp_hashnode *mi_cmacro;/* Macro name for #ifndef around entire
+ file. */
+ const cpp_hashnode *mi_def_cmacro; /* Macro name in the following
+ #define. */
bool skip_elses; /* Can future #else / #elif be skipped? */
bool was_skipping; /* If were skipping on entry. */
int type; /* Most recent conditional for diagnostics. */
where the extension appears to have come from. */
#define DIRECTIVE_TABLE \
- D(define, T_DEFINE = 0, KANDR, IN_I) \
+ D(define, T_DEFINE = 0, KANDR, IN_I | IF_COND) \
D(include, T_INCLUDE, KANDR, INCL | EXPAND) \
D(endif, T_ENDIF, KANDR, COND) \
D(ifdef, T_IFDEF, KANDR, COND | IF_COND) \
/* If we have been requested to expand comments into macros,
then re-enable saving of comments. */
- pfile->state.save_comments =
- ! CPP_OPTION (pfile, discard_comments_in_macro_exp);
+ pfile->state.save_comments
+ = ! CPP_OPTION (pfile, discard_comments_in_macro_exp);
if (pfile->cb.before_define)
pfile->cb.before_define (pfile);
pfile->cb.define (pfile, pfile->directive_line, node);
node->flags &= ~NODE_USED;
+
+ if (pfile->mi_valid
+ && !pfile->mi_cmacro
+ && CPP_OPTION (pfile, warn_header_guard)
+ && node->type == NT_USER_MACRO
+ && node->value.macro
+ && node->value.macro->count == 0
+ && !node->value.macro->fun_like)
+ {
+ cpp_buffer *buffer = pfile->buffer;
+ struct if_stack *ifs = buffer->if_stack;
+ if (ifs
+ && !ifs->next
+ && ifs->mi_cmacro
+ && node != ifs->mi_cmacro)
+ {
+ ifs->mi_def_cmacro = node;
+ ifs->def_loc = pfile->directive_line;
+ }
+ }
}
+ pfile->mi_valid = false;
}
/* Handle #undef. Mark the identifier NT_VOID in the hash table. */
{
pfile->mi_valid = true;
pfile->mi_cmacro = ifs->mi_cmacro;
+ pfile->mi_loc = ifs->line;
+ pfile->mi_def_cmacro = nullptr;
+ if (ifs->mi_def_cmacro && !_cpp_defined_macro_p (pfile->mi_cmacro))
+ {
+ pfile->mi_def_cmacro = ifs->mi_def_cmacro;
+ pfile->mi_def_loc = ifs->def_loc;
+ }
}
buffer->if_stack = ifs->next;
ifs = XOBNEW (&pfile->buffer_ob, struct if_stack);
ifs->line = pfile->directive_line;
+ ifs->def_loc = 0;
ifs->next = buffer->if_stack;
ifs->skip_elses = pfile->state.skipping || !skip;
ifs->was_skipping = pfile->state.skipping;
ifs->mi_cmacro = cmacro;
else
ifs->mi_cmacro = 0;
+ ifs->mi_def_cmacro = nullptr;
pfile->state.skipping = skip;
buffer->if_stack = ifs;
/* Record the inclusion-preventing macro, which could be NULL
meaning no controlling macro. */
if (pfile->mi_valid && file->cmacro == NULL)
- file->cmacro = pfile->mi_cmacro;
+ {
+ file->cmacro = pfile->mi_cmacro;
+ if (pfile->mi_cmacro
+ && pfile->mi_def_cmacro
+ && pfile->cb.get_suggestion)
+ {
+ auto mi_cmacro = (const char *) NODE_NAME (pfile->mi_cmacro);
+ auto mi_def_cmacro = (const char *) NODE_NAME (pfile->mi_def_cmacro);
+ const char *names[] = { mi_def_cmacro, NULL };
+ if (pfile->cb.get_suggestion (pfile, mi_cmacro, names)
+ && cpp_warning_with_line (pfile, CPP_W_HEADER_GUARD,
+ pfile->mi_loc, 0,
+ "header guard \"%s\" followed by "
+ "\"#define\" of a different macro",
+ mi_cmacro))
+ cpp_error_at (pfile, CPP_DL_NOTE, pfile->mi_def_loc,
+ "\"%s\" is defined here; did you mean \"%s\"?",
+ mi_def_cmacro, mi_cmacro);
+ }
+ }
/* Invalidate control macros in the #including file. */
pfile->mi_valid = false;
/* Different -Wimplicit-fallthrough= levels. */
unsigned char cpp_warn_implicit_fallthrough;
+ /* Nonzero means warn about a define of a different macro right after
+ #ifndef/#if !defined header guard directive. */
+ unsigned char warn_header_guard;
+
/* Nonzero means we should look for header.gcc files that remap file
names. */
unsigned char remap;
CPP_W_EXPANSION_TO_DEFINED,
CPP_W_BIDIRECTIONAL,
CPP_W_INVALID_UTF8,
- CPP_W_UNICODE
+ CPP_W_UNICODE,
+ CPP_W_HEADER_GUARD
};
/* Callback for header lookup for HEADER, which is the name of a
CPP_OPTION (pfile, warn_variadic_macros) = 1;
CPP_OPTION (pfile, warn_builtin_macro_redefined) = 1;
CPP_OPTION (pfile, cpp_warn_implicit_fallthrough) = 0;
+ CPP_OPTION (pfile, warn_header_guard) = 0;
/* By default, track locations of tokens resulting from macro
expansion. The '2' means, track the locations with the highest
accuracy. Read the comments for struct
been used. */
bool seen_once_only;
- /* Multiple include optimization. */
+ /* Multiple include optimization and -Wheader-guard warning. */
const cpp_hashnode *mi_cmacro;
const cpp_hashnode *mi_ind_cmacro;
+ const cpp_hashnode *mi_def_cmacro;
+ location_t mi_loc, mi_def_loc;
bool mi_valid;
/* Lexing. */
}
/* True if NODE is a macro for the purposes of ifdef, defined etc. */
-inline bool _cpp_defined_macro_p (cpp_hashnode *node)
+inline bool
+_cpp_defined_macro_p (const cpp_hashnode *node)
{
/* Do not treat conditional macros as being defined. This is due to
the powerpc port using conditional macros for 'vector', 'bool',