diff options
-rw-r--r-- | gdb/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/cp-support.c | 116 | ||||
-rw-r--r-- | gdb/cp-support.h | 2 | ||||
-rw-r--r-- | gdb/linespec.c | 27 |
4 files changed, 139 insertions, 12 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f9a865e..63f0ca4 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 f12d785..684943b 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 b5a5c5f..7ecd201 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 3e943a1..70e27f76 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); } } |