aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-family')
-rw-r--r--gcc/c-family/ChangeLog95
-rw-r--r--gcc/c-family/c-attribs.cc212
-rw-r--r--gcc/c-family/c-common.h4
-rw-r--r--gcc/c-family/c-cppbuiltin.cc77
-rw-r--r--gcc/c-family/c-gimplify.cc27
-rw-r--r--gcc/c-family/c-indentation.cc2
-rw-r--r--gcc/c-family/c-opts.cc11
-rw-r--r--gcc/c-family/c-ubsan.cc311
-rw-r--r--gcc/c-family/c.opt8
-rw-r--r--gcc/c-family/c.opt.urls6
10 files changed, 685 insertions, 68 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index a754525..582a282 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,98 @@
+2025-08-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/121520
+ * c-cppbuiltin.cc (c_cpp_builtins): Properly call cpp_warn
+ for __STDCPP_FLOAT<NN>_T__ if FLOATN_NX_TYPE_NODE (i) is NULL
+ for C++23 for non-extended types and don't call cpp_warn for
+ extended types.
+
+2025-08-18 Indu Bhagat <indu.bhagat@oracle.com>
+
+ * c-attribs.cc (add_no_sanitize_value): Use 'sanitize_code_type'
+ instead of 'unsigned int'.
+ (handle_no_sanitize_attribute): Likewise.
+ (handle_no_sanitize_address_attribute): Likewise.
+ (handle_no_sanitize_thread_attribute): Likewise.
+ (handle_no_address_safety_analysis_attribute): Likewise.
+ * c-common.h (add_no_sanitize_value): Likewise.
+
+2025-08-15 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121552
+ * c.opt (Wnon-c-typedef-for-linkage): New option.
+ * c.opt.urls: Regenerate.
+
+2025-08-15 Jakub Jelinek <jakub@redhat.com>
+
+ PR preprocessor/120778
+ PR target/121520
+ * 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.
+
+2025-08-15 Qing Zhao <qing.zhao@oracle.com>
+
+ * c-gimplify.cc (is_address_with_access_with_size): New function.
+ (ubsan_walk_array_refs_r): Instrument an INDIRECT_REF whose base
+ address is .ACCESS_WITH_SIZE or an address computation whose base
+ address is .ACCESS_WITH_SIZE.
+ * c-ubsan.cc (ubsan_instrument_bounds_pointer_address): New function.
+ (struct factor_t): New structure.
+ (get_factors_from_mul_expr): New function.
+ (get_index_from_offset): New function.
+ (get_index_from_pointer_addr_expr): New function.
+ (is_instrumentable_pointer_array_address): New function.
+ (ubsan_array_ref_instrumented_p): Change prototype.
+ Handle MEM_REF in addtional to ARRAY_REF.
+ (ubsan_maybe_instrument_array_ref): Handle MEM_REF in addtional
+ to ARRAY_REF.
+
+2025-08-15 Qing Zhao <qing.zhao@oracle.com>
+
+ * c-attribs.cc (handle_counted_by_attribute): Accept counted_by
+ attribute for pointer fields.
+
+2025-08-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120776
+ * c-cppbuiltin.cc (c_cpp_builtins): Predefine
+ __cpp_expansion_statements=202506L for C++26.
+
+2025-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * c-indentation.cc (should_warn_for_misleading_indentation):
+ Update for moving diagnostics::context::m_tabstop into
+ diagnostics::column_options.
+ * c-opts.cc (c_common_post_options): Likewise.
+
+2025-08-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/117783
+ * c-cppbuiltin.cc (c_cpp_builtins): Change __cpp_structured_bindings
+ predefined value for C++26 from 202403L to 202411L.
+
+2025-08-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR preprocessor/120778
+ * 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.
+
+2025-08-06 Alexandre Oliva <oliva@adacore.com>
+
+ * c-attribs.cc (handle_hardbool_attribute): Create distinct
+ enumeration types, with structural equality. Handle
+ base type qualifiers.
+
+2025-08-02 Martin Uecker <uecker@tugraz.at>
+
+ * c-attribs.cc (handle_argspec_attribute): Update.
+ (build_arg_spec): New function.
+ (build_attr_access_from_parms): Rewrite `arg spec' handling.
+
2025-07-25 David Malcolm <dmalcolm@redhat.com>
* c-common.cc: Make diagnostics::context::m_source_printing
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 1f4a0df..1e3a94e 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -1128,11 +1128,16 @@ handle_hardbool_attribute (tree *node, tree name, tree args,
}
tree orig = *node;
- *node = build_duplicate_type (orig);
+ /* Drop qualifiers from the base type. Keep attributes, so that, in the odd
+ chance attributes are applicable and relevant to the base type, if they
+ are specified first, or through a typedef, they wouldn't be dropped on the
+ floor here. */
+ tree unqual = build_qualified_type (orig, TYPE_UNQUALIFIED);
+ *node = build_distinct_type_copy (unqual);
TREE_SET_CODE (*node, ENUMERAL_TYPE);
- ENUM_UNDERLYING_TYPE (*node) = orig;
- TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig);
+ ENUM_UNDERLYING_TYPE (*node) = unqual;
+ SET_TYPE_STRUCTURAL_EQUALITY (*node);
tree false_value;
if (args)
@@ -1191,7 +1196,13 @@ handle_hardbool_attribute (tree *node, tree name, tree args,
gcc_checking_assert (!TYPE_CACHED_VALUES_P (*node));
TYPE_VALUES (*node) = values;
- TYPE_NAME (*node) = orig;
+ TYPE_NAME (*node) = unqual;
+
+ if (TYPE_QUALS (orig) != TYPE_QUALS (*node))
+ {
+ *node = build_qualified_type (*node, TYPE_QUALS (orig));
+ TYPE_NAME (*node) = orig;
+ }
return NULL_TREE;
}
@@ -1409,23 +1420,24 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
/* Add FLAGS for a function NODE to no_sanitize_flags in DECL_ATTRIBUTES. */
void
-add_no_sanitize_value (tree node, unsigned int flags)
+add_no_sanitize_value (tree node, sanitize_code_type flags)
{
tree attr = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (node));
if (attr)
{
- unsigned int old_value = tree_to_uhwi (TREE_VALUE (attr));
+ sanitize_code_type old_value =
+ tree_to_sanitize_code_type (TREE_VALUE (attr));
flags |= old_value;
if (flags == old_value)
return;
- TREE_VALUE (attr) = build_int_cst (unsigned_type_node, flags);
+ TREE_VALUE (attr) = build_int_cst (uint64_type_node, flags);
}
else
DECL_ATTRIBUTES (node)
= tree_cons (get_identifier ("no_sanitize"),
- build_int_cst (unsigned_type_node, flags),
+ build_int_cst (uint64_type_node, flags),
DECL_ATTRIBUTES (node));
}
@@ -1436,7 +1448,7 @@ static tree
handle_no_sanitize_attribute (tree *node, tree name, tree args, int,
bool *no_add_attrs)
{
- unsigned int flags = 0;
+ sanitize_code_type flags = 0;
*no_add_attrs = true;
if (TREE_CODE (*node) != FUNCTION_DECL)
{
@@ -1473,7 +1485,7 @@ handle_no_sanitize_address_attribute (tree *node, tree name, tree, int,
if (TREE_CODE (*node) != FUNCTION_DECL)
warning (OPT_Wattributes, "%qE attribute ignored", name);
else
- add_no_sanitize_value (*node, SANITIZE_ADDRESS);
+ add_no_sanitize_value (*node, (sanitize_code_type) SANITIZE_ADDRESS);
return NULL_TREE;
}
@@ -1489,7 +1501,7 @@ handle_no_sanitize_thread_attribute (tree *node, tree name, tree, int,
if (TREE_CODE (*node) != FUNCTION_DECL)
warning (OPT_Wattributes, "%qE attribute ignored", name);
else
- add_no_sanitize_value (*node, SANITIZE_THREAD);
+ add_no_sanitize_value (*node, (sanitize_code_type) SANITIZE_THREAD);
return NULL_TREE;
}
@@ -1506,7 +1518,7 @@ handle_no_address_safety_analysis_attribute (tree *node, tree name, tree, int,
if (TREE_CODE (*node) != FUNCTION_DECL)
warning (OPT_Wattributes, "%qE attribute ignored", name);
else
- add_no_sanitize_value (*node, SANITIZE_ADDRESS);
+ add_no_sanitize_value (*node, (sanitize_code_type) SANITIZE_ADDRESS);
return NULL_TREE;
}
@@ -2906,22 +2918,53 @@ handle_counted_by_attribute (tree *node, tree name,
" declaration %q+D", name, decl);
*no_add_attrs = true;
}
- /* This attribute only applies to field with array type. */
- else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
+ /* This attribute only applies to a field with array type or pointer type. */
+ else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE)
{
error_at (DECL_SOURCE_LOCATION (decl),
- "%qE attribute is not allowed for a non-array field",
- name);
+ "%qE attribute is not allowed for a non-array"
+ " or non-pointer field", name);
*no_add_attrs = true;
}
/* This attribute only applies to a C99 flexible array member type. */
- else if (! c_flexible_array_member_type_p (TREE_TYPE (decl)))
+ else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+ && !c_flexible_array_member_type_p (TREE_TYPE (decl)))
{
error_at (DECL_SOURCE_LOCATION (decl),
"%qE attribute is not allowed for a non-flexible"
" array member field", name);
*no_add_attrs = true;
}
+ /* This attribute cannot be applied to a pointer to void type. */
+ else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == VOID_TYPE)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute is not allowed for a pointer to void",
+ name);
+ *no_add_attrs = true;
+ }
+ /* This attribute cannot be applied to a pointer to function type. */
+ else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == FUNCTION_TYPE)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute is not allowed for a pointer to"
+ " function", name);
+ *no_add_attrs = true;
+ }
+ /* This attribute cannot be applied to a pointer to structure or union
+ with flexible array member. */
+ else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))
+ && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (TREE_TYPE (decl))))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qE attribute is not allowed for a pointer to"
+ " structure or union with flexible array member", name);
+ *no_add_attrs = true;
+ }
/* The argument should be an identifier. */
else if (TREE_CODE (argval) != IDENTIFIER_NODE)
{
@@ -2930,7 +2973,8 @@ handle_counted_by_attribute (tree *node, tree name,
*no_add_attrs = true;
}
/* Issue error when there is a counted_by attribute with a different
- field as the argument for the same flexible array member field. */
+ field as the argument for the same flexible array member or
+ pointer field. */
else if (old_counted_by != NULL_TREE)
{
tree old_fieldname = TREE_VALUE (TREE_VALUE (old_counted_by));
@@ -4120,10 +4164,11 @@ handle_argspec_attribute (tree *, tree, tree args, int, bool *)
{
/* Verify the attribute has one or two arguments and their kind. */
gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST);
- for (tree next = TREE_CHAIN (args); next; next = TREE_CHAIN (next))
+ if (TREE_CHAIN (args))
{
- tree val = TREE_VALUE (next);
- gcc_assert (DECL_P (val) || EXPR_P (val));
+ tree val = TREE_VALUE (TREE_CHAIN (args));
+ gcc_assert (!TREE_CHAIN (TREE_CHAIN (args)));
+ gcc_assert (TYPE_P (val));
}
return NULL_TREE;
}
@@ -5736,6 +5781,71 @@ handle_access_attribute (tree node[3], tree name, tree args, int flags,
return NULL_TREE;
}
+
+/* This function builds a string which is concatenated to SPEC and returns
+ list of variably bounds corresponding to an array/VLA parameter with
+ type TYPE. The string consists of one dollar symbol for each specified
+ variable bound, one asterisk for each unspecified variable bound,
+ a space for an array of unknown size (only possibly for the outermost),
+ and a zero for a zero-sized array.
+
+ The chainof variable bounds starts with the most significant bound.
+ For example, the TYPE T[2][m][3][n] will produce "$$" and (m, (n, nil)). */
+
+static tree
+build_arg_spec (tree type, std::string *spec)
+{
+ while (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) != ARRAY_TYPE)
+ return NULL_TREE;
+
+ tree list = build_arg_spec (TREE_TYPE (type), spec);
+
+ if (!COMPLETE_TYPE_P (type))
+ {
+ (*spec) += ' ';
+ return list;
+ }
+
+ tree mval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+
+ if (!mval)
+ {
+ (*spec) += '0';
+ return list;
+ }
+
+ if (TREE_CODE (mval) == COMPOUND_EXPR
+ && integer_zerop (TREE_OPERAND (mval, 0))
+ && integer_zerop (TREE_OPERAND (mval, 1)))
+ {
+ (*spec) += '*';
+ return list;
+ }
+
+ if (TREE_CODE (mval) == INTEGER_CST)
+ return list;
+
+ /* A variable bound. */
+ (*spec) += '$';
+
+ mval = array_type_nelts_top (type);
+
+ /* Remove NOP_EXPR and SAVE_EXPR to uncover possible PARM_DECLS. */
+ if (TREE_CODE (mval) == NOP_EXPR)
+ mval = TREE_OPERAND (mval, 0);
+ if (TREE_CODE (mval) == SAVE_EXPR)
+ {
+ mval = TREE_OPERAND (mval, 0);
+ if (TREE_CODE (mval) == NOP_EXPR)
+ mval = TREE_OPERAND (mval, 0);
+ }
+
+ return tree_cons (NULL_TREE, mval, list);
+}
+
/* Extract attribute "arg spec" from each FNDECL argument that has it,
build a single attribute access corresponding to all the arguments,
and return the result. SKIP_VOIDPTR set to ignore void* parameters
@@ -5812,15 +5922,16 @@ build_attr_access_from_parms (tree parms, bool skip_voidptr)
argspec = TREE_VALUE (argspec);
/* The attribute arg spec string. */
- tree str = TREE_VALUE (argspec);
- const char *s = TREE_STRING_POINTER (str);
+ const char *s = TREE_STRING_POINTER (TREE_VALUE (argspec));
+ bool static_p = s && (0 == strcmp("static", s));
/* Collect the list of nonnull arguments which use "[static ..]". */
- if (s != NULL && s[0] == '[' && s[1] == 's')
+ if (static_p)
nnlist = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
argpos + 1), nnlist);
- /* Create the attribute access string from the arg spec string,
+ tree argvbs;
+ /* Create the attribute access string from the arg spec data,
optionally followed by position of the VLA bound argument if
it is one. */
{
@@ -5831,21 +5942,52 @@ build_attr_access_from_parms (tree parms, bool skip_voidptr)
specend = 1;
}
- /* Format the access string in place. */
- int len = snprintf (NULL, 0, "%c%u%s",
- attr_access::mode_chars[access_deferred],
- argpos, s);
- spec.resize (specend + len + 1);
- sprintf (&spec[specend], "%c%u%s",
- attr_access::mode_chars[access_deferred],
- argpos, s);
+ spec += attr_access::mode_chars[access_deferred];
+ spec += std::to_string (argpos);
+ spec += '[';
+ tree type = TREE_VALUE (TREE_CHAIN (argspec));
+ argvbs = build_arg_spec (type, &spec);
+
+ /* Postprocess the string to bring it in the format expected
+ by the code handling the access attribute. First, we
+ add 's' if the array was declared as [static ...]. */
+ if (static_p)
+ {
+ size_t send = spec.length();
+
+ if (spec[send - 1] == '[')
+ {
+ spec += 's';
+ }
+ else
+ {
+ /* If there is a symbol, we need to swap the order. */
+ spec += spec[send - 1];
+ spec[send - 1] = 's';
+ }
+ }
+
+ /* If the outermost bound is an integer constant, we need to write
+ the size if it is constant. */
+ if (type && TYPE_DOMAIN (type))
+ {
+ tree mval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+ if (mval && TREE_CODE (mval) == INTEGER_CST)
+ {
+ char buf[40];
+ unsigned HOST_WIDE_INT n = tree_to_uhwi (mval) + 1;
+ sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, n);
+ spec += buf;
+ }
+ }
+ spec += ']';
+
/* Trim the trailing NUL. */
- spec.resize (specend + len);
+ spec.resize (spec.length ());
}
/* The (optional) list of expressions denoting the VLA bounds
N in ARGTYPE <arg>[Ni]...[Nj]...[Nk]. */
- tree argvbs = TREE_CHAIN (argspec);
if (argvbs)
{
spec += ',';
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 7c7e21d..b6021d2 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -747,7 +747,7 @@ enum cxx_dialect {
cxx26
};
-/* The C++ dialect being used. C++98 is the default. */
+/* The C++ dialect being used. C++17 is the default. */
extern enum cxx_dialect cxx_dialect;
/* Maximum template instantiation depth. This limit is rather
@@ -1713,7 +1713,7 @@ extern enum flt_eval_method
excess_precision_mode_join (enum flt_eval_method, enum flt_eval_method);
extern int c_flt_eval_method (bool ts18661_p);
-extern void add_no_sanitize_value (tree node, unsigned int flags);
+extern void add_no_sanitize_value (tree node, sanitize_code_type flags);
extern void maybe_add_include_fixit (rich_location *, const char *, bool);
extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index 4aea902..6b22f9e 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -913,23 +913,42 @@ c_cpp_builtins (cpp_reader *pfile)
/* encoding definitions used by users and libraries */
builtin_define_with_value ("__GNUC_EXECUTION_CHARSET_NAME",
- cpp_get_narrow_charset_name (pfile), 1);
+ cpp_get_narrow_charset_name (pfile), 1);
builtin_define_with_value ("__GNUC_WIDE_EXECUTION_CHARSET_NAME",
- cpp_get_wide_charset_name (pfile), 1);
-
+ cpp_get_wide_charset_name (pfile), 1);
if (c_dialect_cxx ())
- {
- int major;
- parse_basever (&major, NULL, NULL);
- cpp_define_formatted (pfile, "__GNUG__=%d", major);
- }
+ {
+ int major;
+ parse_basever (&major, NULL, NULL);
+ cpp_define_formatted (pfile, "__GNUG__=%d", major);
+ }
/* For stddef.h. They require macros defined in c-common.cc. */
c_stddef_cpp_builtins ();
+ /* Variant of cpp_define which arranges for diagnostics on user #define
+ or #undef of the macros. */
+ auto cpp_define_warn = [] (cpp_reader *pfile, const char *def)
+ {
+ const char *end = strchr (def, '=');
+ cpp_define (pfile, def);
+ cpp_warn (pfile, def, end ? end - def : strlen (def));
+ };
+
if (c_dialect_cxx ())
{
+ /* Treat all cpp_define calls in this block for macros starting
+ with __cpp_ (for C++20 and later) or __STDCPP_ as cpp_define_warn. */
+ auto cpp_define = [=] (cpp_reader *pfile, const char *def)
+ {
+ if ((cxx_dialect >= cxx20 && startswith (def, "__cpp_"))
+ || startswith (def, "__STDCPP_"))
+ cpp_define_warn (pfile, def);
+ else
+ ::cpp_define (pfile, def);
+ };
+
if (flag_weak && SUPPORTS_ONE_ONLY)
cpp_define (pfile, "__GXX_WEAK__=1");
else
@@ -1090,52 +1109,76 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_constexpr_exceptions=202411L");
cpp_define (pfile, "__cpp_static_assert=202306L");
cpp_define (pfile, "__cpp_placeholder_variables=202306L");
- cpp_define (pfile, "__cpp_structured_bindings=202403L");
+ cpp_define (pfile, "__cpp_structured_bindings=202411L");
cpp_define (pfile, "__cpp_deleted_function=202403L");
cpp_define (pfile, "__cpp_variadic_friend=202403L");
cpp_define (pfile, "__cpp_pack_indexing=202311L");
cpp_define (pfile, "__cpp_pp_embed=202502L");
cpp_define (pfile, "__cpp_constexpr_virtual_inheritance=202506L");
cpp_define (pfile, "__cpp_trivial_relocatability=202502L");
+ cpp_define (pfile, "__cpp_expansion_statements=202506L");
}
if (flag_concepts && cxx_dialect > cxx14)
cpp_define (pfile, "__cpp_concepts=202002L");
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_concepts");
if (flag_contracts)
{
cpp_define (pfile, "__cpp_contracts=201906L");
cpp_define (pfile, "__cpp_contracts_literal_semantics=201906L");
cpp_define (pfile, "__cpp_contracts_roles=201906L");
}
+ else if (cxx_dialect >= cxx26)
+ cpp_warn (pfile, "__cpp_contracts");
if (flag_modules)
/* The std-defined value is 201907L, but I don't think we can
claim victory yet. 201810 is the p1103 date. */
cpp_define (pfile, "__cpp_modules=201810L");
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_modules");
if (flag_coroutines)
cpp_define (pfile, "__cpp_impl_coroutine=201902L"); /* n4861, DIS */
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_impl_coroutine");
if (flag_tm)
/* Use a value smaller than the 201505 specified in
the TS, since we don't yet support atomic_cancel. */
cpp_define (pfile, "__cpp_transactional_memory=201500L");
if (flag_sized_deallocation)
cpp_define (pfile, "__cpp_sized_deallocation=201309L");
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_sized_deallocation");
if (aligned_new_threshold)
{
cpp_define (pfile, "__cpp_aligned_new=201606L");
cpp_define_formatted (pfile, "__STDCPP_DEFAULT_NEW_ALIGNMENT__=%d",
aligned_new_threshold);
}
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_aligned_new");
+ if (cxx_dialect >= cxx17)
+ cpp_warn (pfile, "__STDCPP_DEFAULT_NEW_ALIGNMENT__");
if (flag_new_ttp)
cpp_define (pfile, "__cpp_template_template_args=201611L");
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_template_template_args");
if (flag_threadsafe_statics)
cpp_define (pfile, "__cpp_threadsafe_static_init=200806L");
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_threadsafe_static_init");
if (flag_char8_t)
cpp_define (pfile, "__cpp_char8_t=202207L");
+ else if (cxx_dialect >= cxx20)
+ cpp_warn (pfile, "__cpp_char8_t");
#ifndef THREAD_MODEL_SPEC
/* Targets that define THREAD_MODEL_SPEC need to define
__STDCPP_THREADS__ in their config/XXX/XXX-c.c themselves. */
if (cxx_dialect >= cxx11 && strcmp (thread_model, "single") != 0)
cpp_define (pfile, "__STDCPP_THREADS__=1");
+ else
#endif
+ if (cxx_dialect >= cxx11)
+ cpp_warn (pfile, "__STDCPP_THREADS__");
if (flag_implicit_constexpr)
cpp_define (pfile, "__cpp_implicit_constexpr=20211111L");
}
@@ -1284,16 +1327,22 @@ c_cpp_builtins (cpp_reader *pfile)
for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
{
- if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
- continue;
if (c_dialect_cxx ()
&& cxx_dialect > cxx20
&& !floatn_nx_types[i].extended)
{
char name[sizeof ("__STDCPP_FLOAT128_T__=1")];
+ if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
+ {
+ sprintf (name, "__STDCPP_FLOAT%d_T__", floatn_nx_types[i].n);
+ cpp_warn (pfile, name);
+ continue;
+ }
sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n);
- cpp_define (pfile, name);
+ cpp_define_warn (pfile, name);
}
+ else if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
+ continue;
char prefix[20], csuffix[20];
sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
floatn_nx_types[i].extended ? "X" : "");
@@ -1305,10 +1354,12 @@ c_cpp_builtins (cpp_reader *pfile)
if (bfloat16_type_node)
{
if (c_dialect_cxx () && cxx_dialect > cxx20)
- cpp_define (pfile, "__STDCPP_BFLOAT16_T__=1");
+ cpp_define_warn (pfile, "__STDCPP_BFLOAT16_T__=1");
builtin_define_float_constants ("BFLT16", "BF16", "%s",
"BF16", bfloat16_type_node);
}
+ else if (cxx_dialect >= cxx23)
+ cpp_warn (pfile, "__STDCPP_BFLOAT16_T__");
/* For float.h. */
if (targetm.decimal_float_supported_p ())
diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc
index c6fb764..131eca8 100644
--- a/gcc/c-family/c-gimplify.cc
+++ b/gcc/c-family/c-gimplify.cc
@@ -66,6 +66,19 @@ along with GCC; see the file COPYING3. If not see
walk back up, we check that they fit our constraints, and copy them
into temporaries if not. */
+
+/* Check whether TP is an address computation whose base is a call to
+ .ACCESS_WITH_SIZE. */
+
+static bool
+is_address_with_access_with_size (tree tp)
+{
+ if (TREE_CODE (tp) == POINTER_PLUS_EXPR
+ && is_access_with_size_p (TREE_OPERAND (tp, 0)))
+ return true;
+ return false;
+}
+
/* Callback for c_genericize. */
static tree
@@ -121,6 +134,20 @@ ubsan_walk_array_refs_r (tree *tp, int *walk_subtrees, void *data)
walk_tree (&TREE_OPERAND (*tp, 1), ubsan_walk_array_refs_r, pset, pset);
walk_tree (&TREE_OPERAND (*tp, 0), ubsan_walk_array_refs_r, pset, pset);
}
+ else if (TREE_CODE (*tp) == INDIRECT_REF
+ && is_address_with_access_with_size (TREE_OPERAND (*tp, 0)))
+ {
+ ubsan_maybe_instrument_array_ref (&TREE_OPERAND (*tp, 0), false);
+ /* Make sure ubsan_maybe_instrument_array_ref is not called again on
+ the POINTER_PLUS_EXPR, so ensure it is not walked again and walk
+ its subtrees manually. */
+ tree aref = TREE_OPERAND (*tp, 0);
+ pset->add (aref);
+ *walk_subtrees = 0;
+ walk_tree (&TREE_OPERAND (aref, 0), ubsan_walk_array_refs_r, pset, pset);
+ }
+ else if (is_address_with_access_with_size (*tp))
+ ubsan_maybe_instrument_array_ref (tp, true);
return NULL_TREE;
}
diff --git a/gcc/c-family/c-indentation.cc b/gcc/c-family/c-indentation.cc
index bb214fc..d378464 100644
--- a/gcc/c-family/c-indentation.cc
+++ b/gcc/c-family/c-indentation.cc
@@ -330,7 +330,7 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
if (guard_loc == body_loc || body_loc == next_stmt_loc)
return false;
- const unsigned int tab_width = global_dc->m_tabstop;
+ const unsigned int tab_width = global_dc->get_column_options ().m_tabstop;
/* They must be in the same file. */
if (next_stmt_exploc.file != body_exploc.file)
diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index c652e82..0ec30e8 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -959,6 +959,15 @@ c_common_post_options (const char **pfilename)
if (warn_enum_compare == -1)
warn_enum_compare = c_dialect_cxx () ? 1 : 0;
+ /* For C++26 default to -Wkeyword-macro if -Wpedantic. */
+ if (cxx_dialect >= cxx26 && pedantic)
+ {
+ SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+ warn_keyword_macro, 1);
+ if (warn_keyword_macro)
+ cpp_opts->cpp_warn_keyword_macro = warn_keyword_macro;
+ }
+
/* -Wpacked-bitfield-compat is on by default for the C languages. The
warning is issued in stor-layout.cc which is not part of the front-end so
we need to selectively turn it on here. */
@@ -1191,7 +1200,7 @@ c_common_post_options (const char **pfilename)
flag_char8_t = (cxx_dialect >= cxx20) || flag_isoc23;
cpp_opts->unsigned_utf8char = flag_char8_t ? 1 : cpp_opts->unsigned_char;
- cpp_opts->cpp_tabstop = global_dc->m_tabstop;
+ cpp_opts->cpp_tabstop = global_dc->get_column_options ().m_tabstop;
if (flag_extern_tls_init)
{
diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index a4dc310..a64f74e 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -548,38 +548,317 @@ ubsan_instrument_bounds (location_t loc, tree array, tree *index,
*index, bound);
}
-/* Return true iff T is an array that was instrumented by SANITIZE_BOUNDS. */
+
+/* Instrument array bounds for the pointer array address which is
+ a call to .ACCESS_WITH_SIZE. We create special
+ builtin, that gets expanded in the sanopt pass, and make an array
+ dimention of it. POINTER_ADDR is the pointer array's base address.
+ *INDEX is an index to the array.
+ IGNORE_OFF_BY_ONE is true if the POINTER_ADDR is not inside an
+ INDIRECT_REF.
+ Return NULL_TREE if no instrumentation is emitted. */
+
+tree
+ubsan_instrument_bounds_pointer_address (location_t loc, tree pointer_addr,
+ tree *index,
+ bool ignore_off_by_one)
+{
+ tree call = pointer_addr;
+ if (!is_access_with_size_p (call))
+ return NULL_TREE;
+ tree bound = get_bound_from_access_with_size (call);
+
+ if (ignore_off_by_one)
+ bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
+ build_int_cst (TREE_TYPE (bound),
+ 1));
+
+ /* Don't emit instrumentation in the most common cases. */
+ tree idx = NULL_TREE;
+ if (TREE_CODE (*index) == INTEGER_CST)
+ idx = *index;
+ else if (TREE_CODE (*index) == BIT_AND_EXPR
+ && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
+ idx = TREE_OPERAND (*index, 1);
+ if (idx
+ && TREE_CODE (bound) == INTEGER_CST
+ && tree_int_cst_sgn (idx) >= 0
+ && tree_int_cst_lt (idx, bound))
+ return NULL_TREE;
+
+ *index = save_expr (*index);
+
+ /* Create an array_type for the corresponding pointer array. */
+ tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+ /* The array's element type can be get from the return type of the call to
+ .ACCESS_WITH_SIZE. */
+ tree element_type = TREE_TYPE (TREE_TYPE (call));
+ tree array_type = build_array_type (element_type, itype);
+ /* Create a "(T *) 0" tree node to describe the array type. */
+ tree zero_with_type = build_int_cst (build_pointer_type (array_type), 0);
+ return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
+ void_type_node, 3, zero_with_type,
+ *index, bound);
+}
+
+/* This structure is to combine a factor with its parent and its position
+ * in its parent tree. */
+struct factor_t
+{
+ tree factor;
+ tree parent; /* the parent tree of this factor. */
+ int pos; /* the position of this factor in its parent tree. */
+};
+
+/* for a multiply expression like:
+ ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4
+
+ locate all the factors, the parents of the factor and the position of
+ the factor in its parent, and put them to VEC_FACTORS. */
+
+static void
+get_factors_from_mul_expr (tree mult_expr, tree parent,
+ int pos, auto_vec<factor_t> *vec_factors)
+{
+ struct factor_t mult_factor = {0, 0, -1};
+ mult_factor.factor = mult_expr;
+ mult_factor.parent = parent;
+ mult_factor.pos = pos;
+
+ while (CONVERT_EXPR_CODE_P (TREE_CODE (mult_expr)))
+ {
+ mult_factor.parent = mult_expr;
+ mult_factor.pos = 0;
+ mult_expr = TREE_OPERAND (mult_expr, 0);
+ mult_factor.factor = mult_expr;
+ }
+ if (TREE_CODE (mult_expr) != MULT_EXPR)
+ vec_factors->safe_push (mult_factor);
+ else
+ {
+ get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 0), mult_expr,
+ 0, vec_factors);
+ get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 1), mult_expr,
+ 1, vec_factors);
+ }
+}
+
+/* Given an OFFSET expression, and the ELEMENT_SIZE,
+ get the index expression from OFFSET and return it.
+ For example:
+ OFFSET:
+ ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4
+ ELEMENT_SIZE:
+ (sizetype) SAVE_EXPR <n> * 4
+ get the index as (long unsigned int) m, and return it.
+ The INDEX_P holds the pointer to the parent tree of the index,
+ INDEX_N holds the position of the index in its parent. */
+
+static tree
+get_index_from_offset (tree offset, tree *index_p,
+ int *index_n, tree element_size)
+{
+ if (TREE_CODE (offset) != MULT_EXPR)
+ return NULL_TREE;
+
+ auto_vec<factor_t> e_factors, o_factors;
+ get_factors_from_mul_expr (element_size, NULL, -1, &e_factors);
+ get_factors_from_mul_expr (offset, *index_p, *index_n, &o_factors);
+
+ if (e_factors.is_empty () || o_factors.is_empty ())
+ return NULL_TREE;
+
+ bool all_found = true;
+ for (unsigned i = 0; i < e_factors.length (); i++)
+ {
+ factor_t e_size_factor = e_factors[i];
+ bool found = false;
+ for (unsigned j = 0; j < o_factors.length ();)
+ {
+ factor_t o_exp_factor = o_factors[j];
+ if (operand_equal_p (e_size_factor.factor, o_exp_factor.factor))
+ {
+ o_factors.unordered_remove (j);
+ found = true;
+ break;
+ }
+ else
+ j++;
+ }
+ if (!found)
+ all_found = false;
+ }
+
+ if (!all_found)
+ return NULL_TREE;
+
+ if (o_factors.length () != 1)
+ return NULL_TREE;
+
+ *index_p = o_factors[0].parent;
+ *index_n = o_factors[0].pos;
+ return o_factors[0].factor;
+}
+
+/* For an pointer + offset computation expression, such as,
+ .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
+ + (sizetype) ((long unsigned int) index * 4
+ Return the index of this pointer array reference,
+ set the parent tree of INDEX to *INDEX_P.
+ set the operand position of the INDEX in the parent tree to *INDEX_N.
+ If failed, return NULL_TREE. */
+
+static tree
+get_index_from_pointer_addr_expr (tree pointer, tree *index_p, int *index_n)
+{
+ *index_p = NULL_TREE;
+ *index_n = -1;
+ tree call = TREE_OPERAND (pointer, 0);
+ if (!is_access_with_size_p (call))
+ return NULL_TREE;
+
+ /* Get the pointee type of the call to .ACCESS_WITH_SIZE.
+ This should be the element type of the pointer array. */
+ tree pointee_type = TREE_TYPE (TREE_TYPE (call));
+ tree pointee_size = TYPE_SIZE_UNIT (pointee_type);
+
+ tree index_exp = TREE_OPERAND (pointer, 1);
+ *index_p = pointer;
+ *index_n = 1;
+
+ if (!(TREE_CODE (index_exp) != MULT_EXPR
+ && tree_int_cst_equal (pointee_size, integer_one_node)))
+ {
+ while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp)))
+ {
+ *index_p = index_exp;
+ *index_n = 0;
+ index_exp = TREE_OPERAND (index_exp, 0);
+ }
+ index_exp = get_index_from_offset (index_exp, index_p,
+ index_n, pointee_size);
+
+ if (!index_exp)
+ return NULL_TREE;
+ }
+
+ while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp)))
+ {
+ *index_p = index_exp;
+ *index_n = 0;
+ index_exp = TREE_OPERAND (index_exp, 0);
+ }
+
+ return index_exp;
+}
+
+/* Return TRUE when the EXPR is a pointer array address that could be
+ instrumented.
+ We only instrument an address computation similar as the following:
+ .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
+ + (sizetype) ((long unsigned int) index * 4)
+ if the EXPR is instrumentable, return TRUE and
+ set the index to *INDEX.
+ set the .ACCESS_WITH_SIZE to *BASE.
+ set the parent tree of INDEX to *INDEX_P.
+ set the operand position of the INDEX in the parent tree to INDEX_N. */
+
+static bool
+is_instrumentable_pointer_array_address (tree expr, tree *base,
+ tree *index, tree *index_p,
+ int *index_n)
+{
+ /* For a pointer array address as:
+ .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
+ + (sizetype) ((long unsigned int) index * 4)
+ op0 is the call to .ACCESS_WITH_SIZE;
+ op1 is the index. */
+ if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
+ return false;
+
+ tree op0 = TREE_OPERAND (expr, 0);
+ if (!is_access_with_size_p (op0))
+ return false;
+ tree op1 = get_index_from_pointer_addr_expr (expr, index_p, index_n);
+ if (op1 != NULL_TREE)
+ {
+ *base = op0;
+ *index = op1;
+ return true;
+ }
+ return false;
+}
+
+/* Return true iff T is an array or an indirect reference that was
+ instrumented by SANITIZE_BOUNDS. */
bool
-ubsan_array_ref_instrumented_p (const_tree t)
+ubsan_array_ref_instrumented_p (tree t)
{
- if (TREE_CODE (t) != ARRAY_REF)
+ if (TREE_CODE (t) != ARRAY_REF
+ && TREE_CODE (t) != MEM_REF)
return false;
- tree op1 = TREE_OPERAND (t, 1);
- return TREE_CODE (op1) == COMPOUND_EXPR
- && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
- && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
- && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
+ bool is_array = (TREE_CODE (t) == ARRAY_REF);
+ tree op0 = NULL_TREE;
+ tree op1 = NULL_TREE;
+ tree index_p = NULL_TREE;
+ int index_n = 0;
+ if (is_array)
+ {
+ op1 = TREE_OPERAND (t, 1);
+ return TREE_CODE (op1) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
+ && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
+ && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
+ }
+ else if (is_instrumentable_pointer_array_address (t, &op0, &op1,
+ &index_p, &index_n))
+ return TREE_CODE (op1) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
+ && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
+ && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
+
+ return false;
}
-/* Instrument an ARRAY_REF, if it hasn't already been instrumented.
- IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. */
+/* Instrument an ARRAY_REF or an address computation whose base address is
+ a call to .ACCESS_WITH_SIZE, if it hasn't already been instrumented.
+ IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR, or the
+ address computation is not inside a INDIRECT_REF. */
void
ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
{
+ tree e = NULL_TREE;
+ tree op0 = NULL_TREE;
+ tree op1 = NULL_TREE;
+ tree index_p = NULL_TREE; /* the parent tree of INDEX. */
+ int index_n = 0; /* the operand position of INDEX in the parent tree. */
+
if (!ubsan_array_ref_instrumented_p (*expr_p)
&& sanitize_flags_p (SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT)
&& current_function_decl != NULL_TREE)
{
- tree op0 = TREE_OPERAND (*expr_p, 0);
- tree op1 = TREE_OPERAND (*expr_p, 1);
- tree e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0, &op1,
- ignore_off_by_one);
+ if (TREE_CODE (*expr_p) == ARRAY_REF)
+ {
+ op0 = TREE_OPERAND (*expr_p, 0);
+ op1 = TREE_OPERAND (*expr_p, 1);
+ index_p = *expr_p;
+ index_n = 1;
+ e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0,
+ &op1, ignore_off_by_one);
+ }
+ else if (is_instrumentable_pointer_array_address (*expr_p, &op0, &op1,
+ &index_p, &index_n))
+ e = ubsan_instrument_bounds_pointer_address (EXPR_LOCATION (*expr_p),
+ op0, &op1,
+ ignore_off_by_one);
+
+ /* Replace the original INDEX with the instrumented INDEX. */
if (e != NULL_TREE)
- TREE_OPERAND (*expr_p, 1) = build2 (COMPOUND_EXPR, TREE_TYPE (op1),
- e, op1);
+ TREE_OPERAND (index_p, index_n)
+ = build2 (COMPOUND_EXPR, TREE_TYPE (op1), e, op1);
}
}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 12877eb..3f5e2f0 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -964,6 +964,10 @@ Enum(warn_leading_whitespace_kind) String(tabs) Value(2)
EnumValue
Enum(warn_leading_whitespace_kind) String(blanks) Value(3)
+Wkeyword-macro
+C ObjC C++ ObjC++ CPP(cpp_warn_keyword_macro) CppReason(CPP_W_KEYWORD_MACRO) Var(warn_keyword_macro) Init(0) Warning
+Warn about defining or undefining macros with identifiers equal to keywords (or for C++ conditional keywords or standard attribute names).
+
Wleading-whitespace=
C ObjC C++ ObjC++ CPP(cpp_warn_leading_whitespace) CppReason(CPP_W_LEADING_WHITESPACE) Enum(warn_leading_whitespace_kind) Joined RejectNegative Var(warn_leading_whitespace) Init(0) Warning
Warn about leading whitespace style issues on lines except when in raw string literals.
@@ -1106,6 +1110,10 @@ Wnoexcept-type
C++ ObjC++ Warning Var(warn_noexcept_type) LangEnabledBy(C++ ObjC++,Wabi || Wc++17-compat)
Warn if C++17 noexcept function type will change the mangled name of a symbol.
+Wnon-c-typedef-for-linkage
+C++ ObjC++ Var(warn_non_c_typedef_for_linkage) Init(1) Warning
+Warn for non-C compatible unnamed classes with a typedef name for linkage purposes.
+
Wnon-template-friend
C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning
Warn when non-templatized friend functions are declared within a template.
diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls
index 5c97593..e09d51d 100644
--- a/gcc/c-family/c.opt.urls
+++ b/gcc/c-family/c.opt.urls
@@ -508,6 +508,9 @@ UrlSuffix(gcc/Warning-Options.html#index-Winvalid-utf8)
Wjump-misses-init
UrlSuffix(gcc/Warning-Options.html#index-Wjump-misses-init)
+Wkeyword-macro
+UrlSuffix(gcc/Warning-Options.html#index-Wkeyword-macro)
+
Wleading-whitespace=
UrlSuffix(gcc/Warning-Options.html#index-Wleading-whitespace_003d)
@@ -610,6 +613,9 @@ UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-noexcept)
Wnoexcept-type
UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-noexcept-type)
+Wnon-c-typedef-for-linkage
+UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-non-c-typedef-for-linkage)
+
Wnon-template-friend
UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wno-non-template-friend)