From 1290797801825ff96506c8197d301b60154c3250 Mon Sep 17 00:00:00 2001
From: Keith Seitz <keiths@redhat.com>
Date: Mon, 21 Sep 2009 19:46:43 +0000
Subject: [PATCH] 	* cp-support.h (cp_validate_operator): Declare new
 function. 	* cp-support.c (cp_validate_operator): New function. 	*
 linespec.c (decode_compound): For C++ check for a valid operator.

---
 gdb/ChangeLog    |   6 +++
 gdb/cp-support.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/cp-support.h |   2 +
 gdb/linespec.c   |  27 ++++++-----
 4 files changed, 139 insertions(+), 12 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f9a865e7970..63f0ca4ced5 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2009-09-18  Keith Seitz  <keiths@redhat.com>
+
+	* cp-support.h (cp_validate_operator): Declare new function.
+	* cp-support.c (cp_validate_operator): New function.
+	* linespec.c (decode_compound): For C++ check for a valid operator.
+
 2009-09-21  Keith Seitz  <keiths@redhat.com>
 
 	* c-exp.y (qualified_name): Call CHECK_TYPEDEF before deciding
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index f12d785f132..684943bcc25 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -32,6 +32,9 @@
 #include "block.h"
 #include "complaints.h"
 #include "gdbtypes.h"
+#include "exceptions.h"
+#include "expression.h"
+#include "value.h"
 
 #include "safe-ctype.h"
 
@@ -70,6 +73,18 @@ struct cmd_list_element *maint_cplus_cmd_list = NULL;
 static void maint_cplus_command (char *arg, int from_tty);
 static void first_component_command (char *arg, int from_tty);
 
+/* Operator validation.
+   NOTE: Multi-byte operators (usually the assignment variety operator)
+   must appear before the single byte version, i.e., "+=" before "+".  */
+static const char *operator_tokens[] =
+  {
+    "++", "+=", "+", "->*", "->", "--", "-=", "-", "*=", "*", "/=", "/",
+    "%=", "%", "!=", "==", "!", "&&", "<<=", "<<", ">>=", ">>",
+    "<=", "<", ">=", ">", "~", "&=", "&", "|=", "||", "|", "^=", "^",
+    "=", "()", "[]", ",", "new", "delete"
+    /* new[] and delete[] require special whitespace handling */
+  };
+
 /* Return 1 if STRING is clearly already in canonical form.  This
    function is conservative; things which it does not recognize are
    assumed to be non-canonical, and the parser will sort them out
@@ -909,6 +924,107 @@ first_component_command (char *arg, int from_tty)
 
 extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */
 
+#define SKIP_SPACE(P)				\
+  do						\
+  {						\
+    while (*(P) == ' ' || *(P) == '\t')		\
+      ++(P);					\
+  }						\
+  while (0)
+
+/* Returns the length of the operator name or 0 if INPUT does not
+   point to a valid C++ operator.  INPUT should start with "operator".  */
+int
+cp_validate_operator (const char *input)
+{
+  int i;
+  char *copy;
+  const char *p;
+  struct expression *expr;
+  struct value *val;
+  struct gdb_exception except;
+  struct cleanup *old_chain;
+
+  p = input;
+
+  if (strncmp (p, "operator", 8) == 0)
+    {
+      int valid = 0;
+      p += 8;
+
+      SKIP_SPACE (p);
+      for (i = 0; i < sizeof (operator_tokens) / sizeof (operator_tokens[0]);
+	   ++i)
+	{
+	  int length = strlen (operator_tokens[i]);
+	  /* By using strncmp here, we MUST have operator_tokens ordered!
+	     See additional notes where operator_tokens is defined above.  */
+	  if (strncmp (p, operator_tokens[i], length) == 0)
+	    {
+	      const char *op = p;
+	      valid = 1;
+	      p += length;
+
+	      if (strncmp (op, "new", 3) == 0
+		  || strncmp (op, "delete", 6) == 0)
+		{
+
+		  /* Special case: new[] and delete[].  We must be careful
+		     to swallow whitespace before/in "[]".  */
+		  SKIP_SPACE (p);
+
+		  if (*p == '[')
+		    {
+		      ++p;
+		      SKIP_SPACE (p);
+		      if (*p == ']')
+			++p;
+		      else
+			valid = 0;
+		    }
+		}
+
+	      if (valid)
+		return (p - input);
+	    }
+	}
+
+      /* Check input for a conversion operator.  */
+
+      /* Skip past base typename */
+      while (*p != '*' && *p != '&' && *p != 0 && *p != ' ')
+	++p;
+      SKIP_SPACE (p);
+
+      /* Add modifiers '*'/'&' */
+      while (*p == '*' || *p == '&')
+	{
+	  ++p;
+	  SKIP_SPACE (p);
+	}
+
+      /* Check for valid type.  [Remember: input starts with 
+	 "operator".]  */
+      copy = savestring (input + 8, p - input - 8);
+      expr = NULL;
+      val = NULL;
+      TRY_CATCH (except, RETURN_MASK_ALL)
+	{
+	  expr = parse_expression (copy);
+	  val = evaluate_type (expr);
+	}
+
+      xfree (copy);
+      if (expr)
+	xfree (expr);
+
+      if (val != NULL && value_type (val) != NULL)
+	return (p - input);
+    }
+
+  return 0;
+}
+
 void
 _initialize_cp_support (void)
 {
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index b5a5c5fca7f..7ecd201740a 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -72,6 +72,8 @@ extern struct symbol **make_symbol_overload_list (const char *,
 extern struct type *cp_lookup_rtti_type (const char *name,
 					 struct block *block);
 
+extern int cp_validate_operator (const char *input);
+
 /* Functions/variables from cp-namespace.c.  */
 
 extern int cp_is_anonymous (const char *namespace);
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 3e943a18e74..70e27f7683c 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -30,6 +30,7 @@
 #include "value.h"
 #include "completer.h"
 #include "cp-abi.h"
+#include "cp-support.h"
 #include "parser-defs.h"
 #include "block.h"
 #include "objc-lang.h"
@@ -1257,6 +1258,9 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
       /* Move pointer ahead to next double-colon.  */
       while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\''))
 	{
+	  if (current_language->la_language == language_cplus)
+	    p += cp_validate_operator (p);
+
 	  if (p[0] == '<')
 	    {
 	      temp_end = find_template_name_end (p);
@@ -1334,6 +1338,15 @@ decode_compound (char **argptr, int funfirstline, char ***canonical,
 	  while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':')
 	    p++;
 	  /* At this point p->"".  String ended.  */
+	  /* Nope, C++ operators could have spaces in them
+	     ("foo::operator <" or "foo::operator delete []").
+	     I apologize, this is a bit hacky...  */
+	  if (current_language->la_language == language_cplus
+	      && *p == ' ' && p - 8 - *argptr + 1 > 0)
+	    {
+	      /* The above loop has already swallowed "operator".  */
+	      p += cp_validate_operator (p - 8) - 8;
+	    }
 	}
 
       /* Allocate our own copy of the substring between argptr and
@@ -1474,26 +1487,16 @@ find_method (int funfirstline, char ***canonical, char *saved_arg,
     }
   else
     {
-      char *tmp;
-
-      if (is_operator_name (copy))
-	{
-	  tmp = (char *) alloca (strlen (copy + 3) + 9);
-	  strcpy (tmp, "operator ");
-	  strcat (tmp, copy + 3);
-	}
-      else
-	tmp = copy;
       if (not_found_ptr)
         *not_found_ptr = 1;
-      if (tmp[0] == '~')
+      if (copy[0] == '~')
 	cplusplus_error (saved_arg,
 			 "the class `%s' does not have destructor defined\n",
 			 SYMBOL_PRINT_NAME (sym_class));
       else
 	cplusplus_error (saved_arg,
 			 "the class %s does not have any method named %s\n",
-			 SYMBOL_PRINT_NAME (sym_class), tmp);
+			 SYMBOL_PRINT_NAME (sym_class), copy);
     }
 }
 
-- 
GitLab