+/* Issue -Wcast-qual warnings when appropriate. TYPE is the type to
+ which we are casting. OTYPE is the type of the expression being
+ cast. Both TYPE and OTYPE are pointer types. LOC is the location
+ of the cast. -Wcast-qual appeared on the command line. Named
+ address space qualifiers are not handled here, because they result
+ in different warnings. */
+
+static void
+handle_warn_cast_qual (location_t loc, tree type, tree otype)
+{
+ tree in_type = type;
+ tree in_otype = otype;
+ int added = 0;
+ int discarded = 0;
+ bool is_const;
+
+ /* Check that the qualifiers on IN_TYPE are a superset of the
+ qualifiers of IN_OTYPE. The outermost level of POINTER_TYPE
+ nodes is uninteresting and we stop as soon as we hit a
+ non-POINTER_TYPE node on either type. */
+ do
+ {
+ in_otype = TREE_TYPE (in_otype);
+ in_type = TREE_TYPE (in_type);
+
+ /* GNU C allows cv-qualified function types. 'const' means the
+ function is very pure, 'volatile' means it can't return. We
+ need to warn when such qualifiers are added, not when they're
+ taken away. */
+ if (TREE_CODE (in_otype) == FUNCTION_TYPE
+ && TREE_CODE (in_type) == FUNCTION_TYPE)
+ added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype));
+ else
+ discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype)
+ & ~TYPE_QUALS_NO_ADDR_SPACE (in_type));
+ }
+ while (TREE_CODE (in_type) == POINTER_TYPE
+ && TREE_CODE (in_otype) == POINTER_TYPE);
+
+ if (added)
+ warning_at (loc, OPT_Wcast_qual,
+ "cast adds %q#v qualifier to function type", added);
+
+ if (discarded)
+ /* There are qualifiers present in IN_OTYPE that are not present
+ in IN_TYPE. */
+ warning_at (loc, OPT_Wcast_qual,
+ "cast discards %q#v qualifier from pointer target type",
+ discarded);
+
+ if (added || discarded)
+ return;
+
+ /* A cast from **T to const **T is unsafe, because it can cause a
+ const value to be changed with no additional warning. We only
+ issue this warning if T is the same on both sides, and we only
+ issue the warning if there are the same number of pointers on
+ both sides, as otherwise the cast is clearly unsafe anyhow. A
+ cast is unsafe when a qualifier is added at one level and const
+ is not present at all outer levels.
+
+ To issue this warning, we check at each level whether the cast
+ adds new qualifiers not already seen. We don't need to special
+ case function types, as they won't have the same
+ TYPE_MAIN_VARIANT. */
+
+ if (TYPE_MAIN_VARIANT (in_type) != TYPE_MAIN_VARIANT (in_otype))
+ return;
+ if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE)
+ return;
+
+ in_type = type;
+ in_otype = otype;
+ is_const = TYPE_READONLY (TREE_TYPE (in_type));
+ do
+ {
+ in_type = TREE_TYPE (in_type);
+ in_otype = TREE_TYPE (in_otype);
+ if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0
+ && !is_const)
+ {
+ warning_at (loc, OPT_Wcast_qual,
+ "to be safe all intermediate pointers in cast from "
+ "%qT to %qT must be %<const%> qualified",
+ otype, type);
+ break;
+ }
+ if (is_const)
+ is_const = TYPE_READONLY (in_type);
+ }
+ while (TREE_CODE (in_type) == POINTER_TYPE);
+}
+
+/* Build an expression representing a cast to type TYPE of expression EXPR.
+ LOC is the location of the cast-- typically the open paren of the cast. */