aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/tree.c147
2 files changed, 158 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 13e5c10..4134a2ca 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2018-06-18 Nick Clifton <nickc@redhat.com>
+
+ PR 84195
+ * tree.c (escaped_string): New class. Converts an unescaped
+ string into its escaped equivalent.
+ (warn_deprecated_use): Use the new class to convert the
+ deprecation message, if present.
+ (test_escaped_strings): New self test.
+ (test_c_tests): Add test_escaped_strings.
+ * doc/extend.texi (deprecated): Add a note that the
+ deprecation message is affected by the -fmessage-length
+ option, and that control characters will be escaped.
+ (#pragma GCC error): Document this pragma.
+ (#pragma GCC warning): Likewise.
+ * doc/invoke.texi (-fmessage-length): Document this option's
+ effect on the #warning and #error preprocessor directives and
+ the deprecated attribute.
+
2018-06-18 Eric Botcazou <ebotcazou@adacore.com>
* tree.c (decl_value_expr_lookup): Revert latest change.
diff --git a/gcc/tree.c b/gcc/tree.c
index 2d3b26e..6728f1c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12423,13 +12423,103 @@ typedef_variant_p (const_tree type)
return is_typedef_decl (TYPE_NAME (type));
}
+/* A class to handle converting a string that might contain
+ control characters, (eg newline, form-feed, etc), into one
+ in which contains escape sequences instead. */
+
+class escaped_string
+{
+ public:
+ escaped_string () { m_owned = false; m_str = NULL; };
+ ~escaped_string () { if (m_owned) free (m_str); }
+ operator const char *() const { return (const char *) m_str; }
+ void escape (const char *);
+ private:
+ char *m_str;
+ bool m_owned;
+};
+
+/* PR 84195: Replace control characters in "unescaped" with their
+ escaped equivalents. Allow newlines if -fmessage-length has
+ been set to a non-zero value. This is done here, rather than
+ where the attribute is recorded as the message length can
+ change between these two locations. */
+
+void
+escaped_string::escape (const char *unescaped)
+{
+ char *escaped;
+ size_t i, new_i, len;
+
+ if (m_owned)
+ free (m_str);
+
+ m_str = (char *) unescaped;
+ m_owned = false;
+
+ if (unescaped == NULL || *unescaped == 0)
+ return;
+
+ len = strlen (unescaped);
+ escaped = NULL;
+ new_i = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ char c = unescaped[i];
+
+ if (!ISCNTRL (c))
+ {
+ if (escaped)
+ escaped[new_i++] = c;
+ continue;
+ }
+
+ if (c != '\n' || !pp_is_wrapping_line (global_dc->printer))
+ {
+ if (escaped == NULL)
+ {
+ /* We only allocate space for a new string if we
+ actually encounter a control character that
+ needs replacing. */
+ escaped = (char *) xmalloc (len * 2 + 1);
+ strncpy (escaped, unescaped, i);
+ new_i = i;
+ }
+
+ escaped[new_i++] = '\\';
+
+ switch (c)
+ {
+ case '\a': escaped[new_i++] = 'a'; break;
+ case '\b': escaped[new_i++] = 'b'; break;
+ case '\f': escaped[new_i++] = 'f'; break;
+ case '\n': escaped[new_i++] = 'n'; break;
+ case '\r': escaped[new_i++] = 'r'; break;
+ case '\t': escaped[new_i++] = 't'; break;
+ case '\v': escaped[new_i++] = 'v'; break;
+ default: escaped[new_i++] = '?'; break;
+ }
+ }
+ else if (escaped)
+ escaped[new_i++] = c;
+ }
+
+ if (escaped)
+ {
+ escaped[new_i] = 0;
+ m_str = escaped;
+ m_owned = true;
+ }
+}
+
/* Warn about a use of an identifier which was marked deprecated. Returns
whether a warning was given. */
bool
warn_deprecated_use (tree node, tree attr)
{
- const char *msg;
+ escaped_string msg;
if (node == 0 || !warn_deprecated_decl)
return false;
@@ -12451,16 +12541,14 @@ warn_deprecated_use (tree node, tree attr)
attr = lookup_attribute ("deprecated", attr);
if (attr)
- msg = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
- else
- msg = NULL;
+ msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
bool w = false;
if (DECL_P (node))
{
if (msg)
w = warning (OPT_Wdeprecated_declarations,
- "%qD is deprecated: %s", node, msg);
+ "%qD is deprecated: %s", node, (const char *) msg);
else
w = warning (OPT_Wdeprecated_declarations,
"%qD is deprecated", node);
@@ -12485,7 +12573,7 @@ warn_deprecated_use (tree node, tree attr)
{
if (msg)
w = warning (OPT_Wdeprecated_declarations,
- "%qE is deprecated: %s", what, msg);
+ "%qE is deprecated: %s", what, (const char *) msg);
else
w = warning (OPT_Wdeprecated_declarations,
"%qE is deprecated", what);
@@ -12494,11 +12582,12 @@ warn_deprecated_use (tree node, tree attr)
{
if (msg)
w = warning (OPT_Wdeprecated_declarations,
- "type is deprecated: %s", msg);
+ "type is deprecated: %s", (const char *) msg);
else
w = warning (OPT_Wdeprecated_declarations,
"type is deprecated");
}
+
if (w && decl)
inform (DECL_SOURCE_LOCATION (decl), "declared here");
}
@@ -14537,6 +14626,49 @@ test_location_wrappers ()
check_strip_nops (wrapped_int_var, int_var);
}
+/* Check that string escaping works correctly. */
+
+static void
+test_escaped_strings (void)
+{
+ int saved_cutoff;
+ escaped_string msg;
+
+ msg.escape (NULL);
+ /* ASSERT_STREQ does not accept NULL as a valid test
+ result, so we have to use ASSERT_EQ instead. */
+ ASSERT_EQ (NULL, (const char *) msg);
+
+ msg.escape ("");
+ ASSERT_STREQ ("", (const char *) msg);
+
+ msg.escape ("foobar");
+ ASSERT_STREQ ("foobar", (const char *) msg);
+
+ /* Ensure that we have -fmessage-length set to 0. */
+ saved_cutoff = pp_line_cutoff (global_dc->printer);
+ pp_line_cutoff (global_dc->printer) = 0;
+
+ msg.escape ("foo\nbar");
+ ASSERT_STREQ ("foo\\nbar", (const char *) msg);
+
+ msg.escape ("\a\b\f\n\r\t\v");
+ ASSERT_STREQ ("\\a\\b\\f\\n\\r\\t\\v", (const char *) msg);
+
+ /* Now repeat the tests with -fmessage-length set to 5. */
+ pp_line_cutoff (global_dc->printer) = 5;
+
+ /* Note that the newline is not translated into an escape. */
+ msg.escape ("foo\nbar");
+ ASSERT_STREQ ("foo\nbar", (const char *) msg);
+
+ msg.escape ("\a\b\f\n\r\t\v");
+ ASSERT_STREQ ("\\a\\b\\f\n\\r\\t\\v", (const char *) msg);
+
+ /* Restore the original message length setting. */
+ pp_line_cutoff (global_dc->printer) = saved_cutoff;
+}
+
/* Run all of the selftests within this file. */
void
@@ -14547,6 +14679,7 @@ tree_c_tests ()
test_labels ();
test_vector_cst_patterns ();
test_location_wrappers ();
+ test_escaped_strings ();
}
} // namespace selftest