diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 97f91be914ee1a436482d60574b9fe49b910e128..3a072e0a9b0155366b2c24630a5e767ab14bac75 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,11 @@
+2012-03-04  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
+
+	PR fortran/36160
+	* error.c (gfc_widechar_display_length, gfc_wide_display_length):
+	New functions.
+	(print_wide_char_into_buffer): Return length written.
+	(show_locus): Fix locus displayed when wide characters are present.
+
 2012-03-04  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
 	* module.c (gfc_use_module): Improve error message some more.
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index aee9173b66973844248229666edc7a4a66cdd4d5..a8c2b63a6d989b83b307c3b6866db2ca48879e86 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -175,7 +175,39 @@ error_integer (long int i)
 }
 
 
-static void
+static size_t
+gfc_widechar_display_length (gfc_char_t c)
+{
+  if (gfc_wide_is_printable (c))
+    /* Simple ASCII character  */
+    return 1;
+  else if (c < ((gfc_char_t) 1 << 8))
+    /* Displayed as \x??  */
+    return 4;
+  else if (c < ((gfc_char_t) 1 << 16))
+    /* Displayed as \u????  */
+    return 6;
+  else
+    /* Displayed as \U????????  */
+    return 10;
+}
+
+
+/* Length of the ASCII representation of the wide string, escaping wide
+   characters as print_wide_char_into_buffer() does.  */
+
+static size_t
+gfc_wide_display_length (const gfc_char_t *str)
+{
+  size_t i, len;
+
+  for (i = 0, len = 0; str[i]; i++)
+    len += gfc_widechar_display_length (str[i]);
+
+  return len;
+}
+
+static int
 print_wide_char_into_buffer (gfc_char_t c, char *buf)
 {
   static const char xdigit[16] = { '0', '1', '2', '3', '4', '5', '6',
@@ -185,6 +217,7 @@ print_wide_char_into_buffer (gfc_char_t c, char *buf)
     {
       buf[1] = '\0';
       buf[0] = (unsigned char) c;
+      return 1;
     }
   else if (c < ((gfc_char_t) 1 << 8))
     {
@@ -195,6 +228,7 @@ print_wide_char_into_buffer (gfc_char_t c, char *buf)
 
       buf[1] = 'x';
       buf[0] = '\\';
+      return 4;
     }
   else if (c < ((gfc_char_t) 1 << 16))
     {
@@ -209,6 +243,7 @@ print_wide_char_into_buffer (gfc_char_t c, char *buf)
 
       buf[1] = 'u';
       buf[0] = '\\';
+      return 6;
     }
   else
     {
@@ -231,6 +266,7 @@ print_wide_char_into_buffer (gfc_char_t c, char *buf)
 
       buf[1] = 'U';
       buf[0] = '\\';
+      return 10;
     }
 }
 
@@ -326,16 +362,12 @@ show_locus (locus *loc, int c1, int c2)
      show up on the terminal.  Tabs are converted to spaces, and 
      nonprintable characters are converted to a "\xNN" sequence.  */
 
-  /* TODO: Although setting i to the terminal width is clever, it fails
-     to work correctly when nonprintable characters exist.  A better 
-     solution should be found.  */
-
   p = &(lb->line[offset]);
-  i = gfc_wide_strlen (p);
+  i = gfc_wide_display_length (p);
   if (i > terminal_width)
     i = terminal_width - 1;
 
-  for (; i > 0; i--)
+  while (i > 0)
     {
       static char buffer[11];
 
@@ -343,7 +375,7 @@ show_locus (locus *loc, int c1, int c2)
       if (c == '\t')
 	c = ' ';
 
-      print_wide_char_into_buffer (c, buffer);
+      i -= print_wide_char_into_buffer (c, buffer);
       error_string (buffer);
     }
 
@@ -356,13 +388,18 @@ show_locus (locus *loc, int c1, int c2)
   c1 -= offset;
   c2 -= offset;
 
+  p = &(lb->line[offset]);
   for (i = 0; i <= cmax; i++)
     {
+      int spaces, j;
+      spaces = gfc_widechar_display_length (*p++);
+
       if (i == c1)
-	error_char ('1');
+	error_char ('1'), spaces--;
       else if (i == c2)
-	error_char ('2');
-      else
+	error_char ('2'), spaces--;
+
+      for (j = 0; j < spaces; j++)
 	error_char (' ');
     }