* cp-support.h (cp_validate_operator): Declare new function.
authorKeith Seitz <keiths@redhat.com>
Mon, 21 Sep 2009 19:46:43 +0000 (19:46 +0000)
committerKeith Seitz <keiths@redhat.com>
Mon, 21 Sep 2009 19:46:43 +0000 (19:46 +0000)
* cp-support.c (cp_validate_operator): New function.
* linespec.c (decode_compound): For C++ check for a valid operator.

gdb/ChangeLog
gdb/cp-support.c
gdb/cp-support.h
gdb/linespec.c

index f9a865e79704625d7984fda8e83e47a5030fb1d4..63f0ca4ced52eda38db2bd3e42eb4a4819b2f5b2 100644 (file)
@@ -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
index f12d785f13265d770d494d7d5ac09d54fa0ff7a7..684943bcc25bd08b1bf90440b9a7ec90e683ea44 100644 (file)
@@ -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)
 {
index b5a5c5fca7f8b461973d21b4ba2ea7b14a11242c..7ecd201740af3d7db7af24bbdde2c5c793c6688b 100644 (file)
@@ -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);
index 3e943a18e74c088a22b9e870cb3ffac544032d68..70e27f7683c3c22a8306ee28b540f45db5b7f9ea 100644 (file)
@@ -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);
     }
 }