PR ld/12549
[binutils-gdb.git] / gdb / c-exp.y
index e721995a8796f3d60485b66801a702491a5c389e..f6659d47fbec9423bc32207ac67508ef43d64f61 100644 (file)
@@ -1,6 +1,5 @@
 /* YACC parser for C expressions, for GDB.
-   Copyright (C) 1986, 1989-2000, 2003-2004, 2006-2012 Free Software
-   Foundation, Inc.
+   Copyright (C) 1986-2013 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -53,6 +52,9 @@
 #include "dfp.h"
 #include "gdb_assert.h"
 #include "macroscope.h"
+#include "objc-lang.h"
+#include "typeprint.h"
+#include "cp-abi.h"
 
 #define parse_type builtin_type (parse_gdbarch)
 
@@ -159,6 +161,8 @@ void yyerror (char *);
     int *ivec;
 
     struct type_stack *type_stack;
+
+    struct objc_class_str class;
   }
 
 %{
@@ -194,16 +198,24 @@ static void check_parameter_typelist (VEC (type_ptr) *);
    nonterminal "name", which matches either NAME or TYPENAME.  */
 
 %token <tsval> STRING
+%token <sval> NSSTRING         /* ObjC Foundation "NSString" literal */
+%token SELECTOR                        /* ObjC "@selector" pseudo-operator   */
 %token <tsval> CHAR
 %token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence. */
 %token <ssym> UNKNOWN_CPP_NAME
 %token <voidval> COMPLETE
 %token <tsym> TYPENAME
+%token <class> CLASSNAME       /* ObjC Class name */
 %type <sval> name
 %type <svec> string_exp
 %type <ssym> name_not_typename
 %type <tsym> typename
 
+ /* This is like a '[' token, but is only generated when parsing
+    Objective C.  This lets us reuse the same parser without
+    erroneously parsing ObjC-specific expressions in C.  */
+%token OBJC_LBRAC
+
 /* A NAME_OR_INT is a symbol which is not known in the symbol table,
    but which would parse as a valid number in the current input radix.
    E.g. "c" when input_radix==16.  Depending on the parse, it will be
@@ -219,6 +231,8 @@ static void check_parameter_typelist (VEC (type_ptr) *);
 %type <sval> operator
 %token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST
 %token ENTRY
+%token TYPEOF
+%token DECLTYPE
 
 /* Special type cases, put in to allow the parser to distinguish different
    legal basetypes.  */
@@ -249,7 +263,7 @@ static void check_parameter_typelist (VEC (type_ptr) *);
 %left '+' '-'
 %left '*' '/' '%'
 %right UNARY INCREMENT DECREMENT
-%right ARROW ARROW_STAR '.' DOT_STAR '[' '('
+%right ARROW ARROW_STAR '.' DOT_STAR '[' OBJC_LBRAC '('
 %token <ssym> BLOCKNAME 
 %token <bval> FILENAME
 %type <bval> block
@@ -268,6 +282,20 @@ type_exp:  type
                        { write_exp_elt_opcode(OP_TYPE);
                          write_exp_elt_type($1);
                          write_exp_elt_opcode(OP_TYPE);}
+       |       TYPEOF '(' exp ')'
+                       {
+                         write_exp_elt_opcode (OP_TYPEOF);
+                       }
+       |       TYPEOF '(' type ')'
+                       {
+                         write_exp_elt_opcode (OP_TYPE);
+                         write_exp_elt_type ($3);
+                         write_exp_elt_opcode (OP_TYPE);
+                       }
+       |       DECLTYPE '(' exp ')'
+                       {
+                         write_exp_elt_opcode (OP_DECLTYPE);
+                       }
        ;
 
 /* Expressions, including the comma operator.  */
@@ -395,6 +423,78 @@ exp        :       exp '[' exp1 ']'
                        { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
        ;
 
+exp    :       exp OBJC_LBRAC exp1 ']'
+                       { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+       ;
+
+/*
+ * The rules below parse ObjC message calls of the form:
+ *     '[' target selector {':' argument}* ']'
+ */
+
+exp    :       OBJC_LBRAC TYPENAME
+                       {
+                         CORE_ADDR class;
+
+                         class = lookup_objc_class (parse_gdbarch,
+                                                    copy_name ($2.stoken));
+                         if (class == 0)
+                           error (_("%s is not an ObjC Class"),
+                                  copy_name ($2.stoken));
+                         write_exp_elt_opcode (OP_LONG);
+                         write_exp_elt_type (parse_type->builtin_int);
+                         write_exp_elt_longcst ((LONGEST) class);
+                         write_exp_elt_opcode (OP_LONG);
+                         start_msglist();
+                       }
+               msglist ']'
+                       { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+                         end_msglist();
+                         write_exp_elt_opcode (OP_OBJC_MSGCALL);
+                       }
+       ;
+
+exp    :       OBJC_LBRAC CLASSNAME
+                       {
+                         write_exp_elt_opcode (OP_LONG);
+                         write_exp_elt_type (parse_type->builtin_int);
+                         write_exp_elt_longcst ((LONGEST) $2.class);
+                         write_exp_elt_opcode (OP_LONG);
+                         start_msglist();
+                       }
+               msglist ']'
+                       { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+                         end_msglist();
+                         write_exp_elt_opcode (OP_OBJC_MSGCALL);
+                       }
+       ;
+
+exp    :       OBJC_LBRAC exp
+                       { start_msglist(); }
+               msglist ']'
+                       { write_exp_elt_opcode (OP_OBJC_MSGCALL);
+                         end_msglist();
+                         write_exp_elt_opcode (OP_OBJC_MSGCALL);
+                       }
+       ;
+
+msglist :      name
+                       { add_msglist(&$1, 0); }
+       |       msgarglist
+       ;
+
+msgarglist :   msgarg
+       |       msgarglist msgarg
+       ;
+
+msgarg :       name ':' exp
+                       { add_msglist(&$1, 1); }
+       |       ':' exp /* Unnamed arg.  */
+                       { add_msglist(0, 1);   }
+       |       ',' exp /* Variable number of args.  */
+                       { add_msglist(0, 0);   }
+       ;
+
 exp    :       exp '(' 
                        /* This is to save the value of arglist_len
                           being accumulated by an outer function call.  */
@@ -625,6 +725,13 @@ exp        :       VARIABLE
                        }
        ;
 
+exp    :       SELECTOR '(' name ')'
+                       {
+                         write_exp_elt_opcode (OP_OBJC_SELECTOR);
+                         write_exp_string ($3);
+                         write_exp_elt_opcode (OP_OBJC_SELECTOR); }
+       ;
+
 exp    :       SIZEOF '(' type ')'     %prec UNARY
                        { write_exp_elt_opcode (OP_LONG);
                          write_exp_elt_type (lookup_signed_typename
@@ -722,6 +829,14 @@ exp        :       string_exp
                        }
        ;
 
+exp     :      NSSTRING        /* ObjC NextStep NSString constant
+                                * of the form '@' '"' string '"'.
+                                */
+                       { write_exp_elt_opcode (OP_OBJC_NSSTRING);
+                         write_exp_string ($1);
+                         write_exp_elt_opcode (OP_OBJC_NSSTRING); }
+       ;
+
 /* C++.  */
 exp     :       TRUEKEYWORD    
                         { write_exp_elt_opcode (OP_LONG);
@@ -756,7 +871,7 @@ block       :       BLOCKNAME
 block  :       block COLONCOLON name
                        { struct symbol *tem
                            = lookup_symbol (copy_name ($3), $1,
-                                            VAR_DOMAIN, (int *) NULL);
+                                            VAR_DOMAIN, NULL);
                          if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
                            error (_("No function \"%s\" in specified context."),
                                   copy_name ($3));
@@ -781,7 +896,7 @@ variable:   name_not_typename ENTRY
 variable:      block COLONCOLON name
                        { struct symbol *sym;
                          sym = lookup_symbol (copy_name ($3), $1,
-                                              VAR_DOMAIN, (int *) NULL);
+                                              VAR_DOMAIN, NULL);
                          if (sym == 0)
                            error (_("No symbol \"%s\" in specified context."),
                                   copy_name ($3));
@@ -808,7 +923,7 @@ qualified_name:     TYPENAME COLONCOLON name
                              && TYPE_CODE (type) != TYPE_CODE_UNION
                              && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
                            error (_("`%s' is not defined as an aggregate type."),
-                                  TYPE_NAME (type));
+                                  TYPE_SAFE_NAME (type));
 
                          write_exp_elt_opcode (OP_SCOPE);
                          write_exp_elt_type (type);
@@ -824,7 +939,7 @@ qualified_name:     TYPENAME COLONCOLON name
                              && TYPE_CODE (type) != TYPE_CODE_UNION
                              && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
                            error (_("`%s' is not defined as an aggregate type."),
-                                  TYPE_NAME (type));
+                                  TYPE_SAFE_NAME (type));
 
                          tmp_token.ptr = (char*) alloca ($4.length + 2);
                          tmp_token.length = $4.length + 1;
@@ -844,7 +959,7 @@ qualified_name:     TYPENAME COLONCOLON name
                          char *copy = copy_name ($3);
                          error (_("No type \"%s\" within class "
                                   "or namespace \"%s\"."),
-                                copy, TYPE_NAME ($1.type));
+                                copy, TYPE_SAFE_NAME ($1.type));
                        }
        ;
 
@@ -857,7 +972,7 @@ variable:   qualified_name
 
                          sym =
                            lookup_symbol (name, (const struct block *) NULL,
-                                          VAR_DOMAIN, (int *) NULL);
+                                          VAR_DOMAIN, NULL);
                          if (sym)
                            {
                              write_exp_elt_opcode (OP_VAR_VALUE);
@@ -1010,8 +1125,12 @@ direct_abs_decl: '(' abs_decl ')'
 
 array_mod:     '[' ']'
                        { $$ = -1; }
+       |       OBJC_LBRAC ']'
+                       { $$ = -1; }
        |       '[' INT ']'
                        { $$ = $2.val; }
+       |       OBJC_LBRAC INT ']'
+                       { $$ = $2.val; }
        ;
 
 func_mod:      '(' ')'
@@ -1149,15 +1268,59 @@ typebase  /* Implements (approximately): (type-qualifier)* type-specifier */
        |       STRUCT name
                        { $$ = lookup_struct (copy_name ($2),
                                              expression_context_block); }
+       |       STRUCT COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_STRUCT, "", 0);
+                         $$ = NULL;
+                       }
+       |       STRUCT name COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_STRUCT, $2.ptr,
+                                              $2.length);
+                         $$ = NULL;
+                       }
        |       CLASS name
                        { $$ = lookup_struct (copy_name ($2),
                                              expression_context_block); }
+       |       CLASS COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_CLASS, "", 0);
+                         $$ = NULL;
+                       }
+       |       CLASS name COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_CLASS, $2.ptr,
+                                              $2.length);
+                         $$ = NULL;
+                       }
        |       UNION name
                        { $$ = lookup_union (copy_name ($2),
                                             expression_context_block); }
+       |       UNION COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_UNION, "", 0);
+                         $$ = NULL;
+                       }
+       |       UNION name COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_UNION, $2.ptr,
+                                              $2.length);
+                         $$ = NULL;
+                       }
        |       ENUM name
                        { $$ = lookup_enum (copy_name ($2),
                                            expression_context_block); }
+       |       ENUM COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_ENUM, "", 0);
+                         $$ = NULL;
+                       }
+       |       ENUM name COMPLETE
+                       {
+                         mark_completion_tag (TYPE_CODE_ENUM, $2.ptr,
+                                              $2.length);
+                         $$ = NULL;
+                       }
        |       UNSIGNED typename
                        { $$ = lookup_unsigned_typename (parse_language,
                                                         parse_gdbarch,
@@ -1277,6 +1440,10 @@ operator:        OPERATOR NEW
                        { $$ = operator_stoken (" new[]"); }
        |       OPERATOR DELETE '[' ']'
                        { $$ = operator_stoken (" delete[]"); }
+       |       OPERATOR NEW OBJC_LBRAC ']'
+                       { $$ = operator_stoken (" new[]"); }
+       |       OPERATOR DELETE OBJC_LBRAC ']'
+                       { $$ = operator_stoken (" delete[]"); }
        |       OPERATOR '+'
                        { $$ = operator_stoken ("+"); }
        |       OPERATOR '-'
@@ -1373,12 +1540,15 @@ operator:       OPERATOR NEW
                        { $$ = operator_stoken ("()"); }
        |       OPERATOR '[' ']'
                        { $$ = operator_stoken ("[]"); }
+       |       OPERATOR OBJC_LBRAC ']'
+                       { $$ = operator_stoken ("[]"); }
        |       OPERATOR conversion_type_id
                        { char *name;
                          long length;
                          struct ui_file *buf = mem_fileopen ();
 
-                         c_print_type ($2, NULL, buf, -1, 0);
+                         c_print_type ($2, NULL, buf, -1, 0,
+                                       &type_print_raw_options);
                          name = ui_file_xstrdup (buf, &length);
                          ui_file_delete (buf);
                          $$ = operator_stoken (name);
@@ -1407,11 +1577,15 @@ name_not_typename :     NAME
  */
        |       operator
                        {
+                         struct field_of_this_result is_a_field_of_this;
+
                          $$.stoken = $1;
                          $$.sym = lookup_symbol ($1.ptr,
                                                  expression_context_block,
                                                  VAR_DOMAIN,
-                                                 &$$.is_a_field_of_this);
+                                                 &is_a_field_of_this);
+                         $$.is_a_field_of_this
+                           = is_a_field_of_this.type != NULL;
                        }
        |       UNKNOWN_CPP_NAME
        ;
@@ -1881,6 +2055,7 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
 {
   int quote;
   enum c_string_type type;
+  int is_objc = 0;
 
   /* Build the gdb internal form of the input string in tempbuf.  Note
      that the buffer is null byte terminated *only* for the
@@ -1913,6 +2088,13 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
       type = C_STRING_32;
       ++tokptr;
     }
+  else if (*tokptr == '@')
+    {
+      /* An Objective C string.  */
+      is_objc = 1;
+      type = C_STRING;
+      ++tokptr;
+    }
   else
     type = C_STRING;
 
@@ -1960,7 +2142,7 @@ parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
 
   *outptr = tokptr;
 
-  return quote == '"' ? STRING : CHAR;
+  return quote == '"' ? (is_objc ? NSSTRING : STRING) : CHAR;
 }
 
 /* This is used to associate some attributes with a token.  */
@@ -2059,7 +2241,13 @@ static const struct token ident_tokens[] =
     {"const_cast", CONST_CAST, OP_NULL, FLAG_CXX },
     {"dynamic_cast", DYNAMIC_CAST, OP_NULL, FLAG_CXX },
     {"static_cast", STATIC_CAST, OP_NULL, FLAG_CXX },
-    {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, FLAG_CXX }
+    {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, FLAG_CXX },
+
+    {"__typeof__", TYPEOF, OP_TYPEOF, 0 },
+    {"__typeof", TYPEOF, OP_TYPEOF, 0 },
+    {"typeof", TYPEOF, OP_TYPEOF, FLAG_SHADOW },
+    {"__decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX },
+    {"decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX | FLAG_SHADOW }
   };
 
 /* When we find that lexptr (the global var defined in parse.c) is
@@ -2214,7 +2402,7 @@ lex_one_token (void)
 
        lexptr += 2;
        yylval.opcode = tokentab2[i].opcode;
-       if (in_parse_field && tokentab2[i].token == ARROW)
+       if (parse_completion && tokentab2[i].token == ARROW)
          last_was_structop = 1;
        return tokentab2[i].token;
       }
@@ -2253,6 +2441,8 @@ lex_one_token (void)
     case '(':
       paren_depth++;
       lexptr++;
+      if (parse_language->la_language == language_objc && c == '[')
+       return OBJC_LBRAC;
       return c;
 
     case ']':
@@ -2275,7 +2465,7 @@ lex_one_token (void)
       /* Might be a floating point number.  */
       if (lexptr[1] < '0' || lexptr[1] > '9')
        {
-         if (in_parse_field)
+         if (parse_completion)
            last_was_structop = 1;
          goto symbol;          /* Nope, must be a symbol. */
        }
@@ -2349,6 +2539,20 @@ lex_one_token (void)
        char *p = &tokstart[1];
        size_t len = strlen ("entry");
 
+       if (parse_language->la_language == language_objc)
+         {
+           size_t len = strlen ("selector");
+
+           if (strncmp (p, "selector", len) == 0
+               && (p[len] == '\0' || isspace (p[len])))
+             {
+               lexptr = p + len;
+               return SELECTOR;
+             }
+           else if (*p == '"')
+             goto parse_string;
+         }
+
        while (isspace (*p))
          p++;
        if (strncmp (p, "entry", len) == 0 && !isalnum (p[len])
@@ -2388,6 +2592,8 @@ lex_one_token (void)
       /* Fall through.  */
     case '\'':
     case '"':
+
+    parse_string:
       {
        int host_len;
        int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval,
@@ -2488,7 +2694,7 @@ lex_one_token (void)
 
        if ((ident_tokens[i].flags & FLAG_SHADOW) != 0)
          {
-           int is_a_field_of_this = 0;
+           struct field_of_this_result is_a_field_of_this;
 
            if (lookup_symbol (copy, expression_context_block,
                               VAR_DOMAIN,
@@ -2511,8 +2717,12 @@ lex_one_token (void)
   if (*tokstart == '$')
     return VARIABLE;
 
-  if (in_parse_field && *lexptr == '\0')
+  if (parse_completion && *lexptr == '\0')
     saw_name_at_eof = 1;
+
+  yylval.ssym.stoken = yylval.sval;
+  yylval.ssym.sym = NULL;
+  yylval.ssym.is_a_field_of_this = 0;
   return NAME;
 }
 
@@ -2541,22 +2751,26 @@ static struct obstack name_obstack;
    in which lookups start; this can be NULL to mean the global
    scope.  */
 static int
-classify_name (struct block *block)
+classify_name (const struct block *block)
 {
   struct symbol *sym;
   char *copy;
-  int is_a_field_of_this = 0;
+  struct field_of_this_result is_a_field_of_this;
 
   copy = copy_name (yylval.sval);
 
+  /* Initialize this in case we *don't* use it in this call; that way
+     we can refer to it unconditionally below.  */
+  memset (&is_a_field_of_this, 0, sizeof (is_a_field_of_this));
+
   sym = lookup_symbol (copy, block, VAR_DOMAIN, 
-                      parse_language->la_language == language_cplus
-                      ? &is_a_field_of_this : (int *) NULL);
+                      parse_language->la_name_of_this
+                      ? &is_a_field_of_this : NULL);
 
   if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
     {
       yylval.ssym.sym = sym;
-      yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+      yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
       return BLOCKNAME;
     }
   else if (!sym)
@@ -2570,6 +2784,26 @@ classify_name (struct block *block)
          yylval.bval = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
          return FILENAME;
        }
+
+      /* If we found a field of 'this', we might have erroneously
+        found a constructor where we wanted a type name.  Handle this
+        case by noticing that we found a constructor and then look up
+        the type tag instead.  */
+      if (is_a_field_of_this.type != NULL
+         && is_a_field_of_this.fn_field != NULL
+         && TYPE_FN_FIELD_CONSTRUCTOR (is_a_field_of_this.fn_field->fn_fields,
+                                       0))
+       {
+         struct field_of_this_result inner_is_a_field_of_this;
+
+         sym = lookup_symbol (copy, block, STRUCT_DOMAIN,
+                              &inner_is_a_field_of_this);
+         if (sym != NULL)
+           {
+             yylval.tsym.type = SYMBOL_TYPE (sym);
+             return TYPENAME;
+           }
+       }
     }
 
   if (sym && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
@@ -2584,6 +2818,20 @@ classify_name (struct block *block)
   if (yylval.tsym.type != NULL)
     return TYPENAME;
 
+  /* See if it's an ObjC classname.  */
+  if (parse_language->la_language == language_objc && !sym)
+    {
+      CORE_ADDR Class = lookup_objc_class (parse_gdbarch, copy);
+      if (Class)
+       {
+         yylval.class.class = Class;
+         sym = lookup_struct_typedef (copy, expression_context_block, 1);
+         if (sym)
+           yylval.class.type = SYMBOL_TYPE (sym);
+         return CLASSNAME;
+       }
+    }
+
   /* Input names that aren't symbols but ARE valid hex numbers, when
      the input radix permits them, can be names or numbers depending
      on the parse.  Note we support radixes > 16 here.  */
@@ -2596,18 +2844,18 @@ classify_name (struct block *block)
       if (hextype == INT)
        {
          yylval.ssym.sym = sym;
-         yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+         yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
          return NAME_OR_INT;
        }
     }
 
   /* Any other kind of symbol */
   yylval.ssym.sym = sym;
-  yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+  yylval.ssym.is_a_field_of_this = is_a_field_of_this.type != NULL;
 
   if (sym == NULL
       && parse_language->la_language == language_cplus
-      && !is_a_field_of_this
+      && is_a_field_of_this.type == NULL
       && !lookup_minimal_symbol (copy, NULL, NULL))
     return UNKNOWN_CPP_NAME;
 
@@ -2615,26 +2863,26 @@ classify_name (struct block *block)
 }
 
 /* Like classify_name, but used by the inner loop of the lexer, when a
-   name might have already been seen.  FIRST_NAME is true if the token
-   in `yylval' is the first component of a name, false otherwise.  */
+   name might have already been seen.  CONTEXT is the context type, or
+   NULL if this is the first component of a name.  */
 
 static int
-classify_inner_name (struct block *block, int first_name)
+classify_inner_name (const struct block *block, struct type *context)
 {
-  struct type *type, *new_type;
+  struct type *type;
   char *copy;
 
-  if (first_name)
+  if (context == NULL)
     return classify_name (block);
 
-  type = check_typedef (yylval.tsym.type);
+  type = check_typedef (context);
   if (TYPE_CODE (type) != TYPE_CODE_STRUCT
       && TYPE_CODE (type) != TYPE_CODE_UNION
       && TYPE_CODE (type) != TYPE_CODE_NAMESPACE)
     return ERROR;
 
-  copy = copy_name (yylval.tsym.stoken);
-  yylval.ssym.sym = cp_lookup_nested_symbol (yylval.tsym.type, copy, block);
+  copy = copy_name (yylval.ssym.stoken);
+  yylval.ssym.sym = cp_lookup_nested_symbol (type, copy, block);
   if (yylval.ssym.sym == NULL)
     return ERROR;
 
@@ -2649,7 +2897,6 @@ classify_inner_name (struct block *block, int first_name)
       return TYPENAME;
 
     default:
-      yylval.ssym.is_a_field_of_this = 0;
       return NAME;
     }
   internal_error (__FILE__, __LINE__, _("not reached"));
@@ -2671,6 +2918,7 @@ yylex (void)
 {
   token_and_value current;
   int first_was_coloncolon, last_was_coloncolon, first_iter;
+  struct type *context_type = NULL;
 
   if (popping && !VEC_empty (token_and_value, token_fifo))
     {
@@ -2692,7 +2940,10 @@ yylex (void)
   last_was_coloncolon = first_was_coloncolon;
   obstack_free (&name_obstack, obstack_base (&name_obstack));
   if (!last_was_coloncolon)
-    obstack_grow (&name_obstack, yylval.sval.ptr, yylval.sval.length);
+    {
+      obstack_grow (&name_obstack, yylval.sval.ptr, yylval.sval.length);
+      context_type = yylval.tsym.type;
+    }
   current.value = yylval;
   first_iter = 1;
   while (1)
@@ -2709,7 +2960,7 @@ yylex (void)
          classification = classify_inner_name (first_was_coloncolon
                                                ? NULL
                                                : expression_context_block,
-                                               first_iter);
+                                               context_type);
          /* We keep going until we either run out of names, or until
             we have a qualified name which is not a type.  */
          if (classification != TYPENAME && classification != NAME)
@@ -2720,7 +2971,7 @@ yylex (void)
            }
 
          /* Update the partial name we are constructing.  */
-         if (!first_iter)
+         if (context_type != NULL)
            {
              /* We don't want to put a leading "::" into the name.  */
              obstack_grow_str (&name_obstack, "::");
@@ -2734,6 +2985,11 @@ yylex (void)
          current.token = classification;
 
          last_was_coloncolon = 0;
+         
+         if (classification == NAME)
+           break;
+
+         context_type = yylval.tsym.type;
        }
       else if (next.token == COLONCOLON && !last_was_coloncolon)
        last_was_coloncolon = 1;