C++ PATCH: Fix namespace lookup bug

Mark Mitchell mark@codesourcery.com
Tue Dec 31 19:14:00 GMT 2002


This patch fixes the problem that Gaby, Neil, and I discussed today;
names before "::" are looked up ignoring objects, functions, and
enumerators that might be found.

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2002-12-31  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (LOOKUP_TEMPLATES_EXPECTED): Remove.
	(lookup_name_namespace_only): Likewise.
	(begin_only_namespace_names): Likewise.
	(end_only_namespace_names): Likewise.
	* decl.c (only_namespace_names): Remove.
	(qualify_lookup): Do not check LOOKUP_TEMPLATES_EXPECTED.
	(lookup_name_real): Do not check only_namespace_names.
	(lookup_name_namespace_only): Remove.
	(begin_only_namespace_names): Likewise.
	(end_only_namespace_names): Likewise.
	* parser.c (cp_parser_nested_name_specifier_opt): Handle erroneous
	nested-name-specifiers more gracefully.
	(cp_parser_class_or_namespace_name): Avoid looking up namespace
	names when they cannot possibly appear.
	(cp_parser_template_name): Adjust call to cp_parser_lookup_name.
	(cp_parser_elaborated_type_specifier): Likewise.
	(cp_parser_namespace_name): Only look for namespace names.
	(cp_parser_lookup_name): Add is_namespace parameter.
	(cp_parser_lookup_name_simple): Adjust call to
	cp_parser_lookup_name.

2002-12-31  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/parse/namespace1.C: New test.

Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.791
diff -c -5 -p -r1.791 cp-tree.h
*** cp/cp-tree.h	31 Dec 2002 19:43:14 -0000	1.791
--- cp/cp-tree.h	1 Jan 2003 02:40:24 -0000
*************** enum overload_flags { NO_SPECIAL = 0, DT
*** 3383,3395 ****
     These are used in global lookup to support elaborated types and
     qualifiers.
  
     LOOKUP_PREFER_TYPES means not to accept objects, and possibly namespaces.
     LOOKUP_PREFER_NAMESPACES means not to accept objects, and possibly types.
!    LOOKUP_PREFER_BOTH means class-or-namespace-name.
!    LOOKUP_TEMPLATES_EXPECTED means that class templates also count
!      as types.  */
  
  #define LOOKUP_PROTECT (1)
  #define LOOKUP_COMPLAIN (2)
  #define LOOKUP_NORMAL (3)
  #define LOOKUP_NONVIRTUAL (8)
--- 3383,3393 ----
     These are used in global lookup to support elaborated types and
     qualifiers.
  
     LOOKUP_PREFER_TYPES means not to accept objects, and possibly namespaces.
     LOOKUP_PREFER_NAMESPACES means not to accept objects, and possibly types.
!    LOOKUP_PREFER_BOTH means class-or-namespace-name.  */
  
  #define LOOKUP_PROTECT (1)
  #define LOOKUP_COMPLAIN (2)
  #define LOOKUP_NORMAL (3)
  #define LOOKUP_NONVIRTUAL (8)
*************** enum overload_flags { NO_SPECIAL = 0, DT
*** 3401,3411 ****
  #define LOOKUP_DESTRUCTOR (512)
  #define LOOKUP_NO_TEMP_BIND (1024)
  #define LOOKUP_PREFER_TYPES (2048)
  #define LOOKUP_PREFER_NAMESPACES (4096)
  #define LOOKUP_PREFER_BOTH (6144)
- #define LOOKUP_TEMPLATES_EXPECTED (8192)
  
  #define LOOKUP_NAMESPACES_ONLY(F)  \
    (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
  #define LOOKUP_TYPES_ONLY(F)  \
    (!((F) & LOOKUP_PREFER_NAMESPACES) && ((F) & LOOKUP_PREFER_TYPES))
--- 3399,3408 ----
*************** extern tree lookup_name_nonclass		PARAMS
*** 3736,3749 ****
  extern tree lookup_function_nonclass            PARAMS ((tree, tree));
  extern tree lookup_qualified_name               (tree, tree, bool, int);
  extern tree lookup_name				PARAMS ((tree, int));
  extern tree lookup_name_current_level		PARAMS ((tree));
  extern tree lookup_type_current_level		PARAMS ((tree));
- extern tree lookup_name_namespace_only          PARAMS ((tree));
  extern tree lookup_name_real                    (tree, int, int, int, int);
- extern void begin_only_namespace_names          PARAMS ((void));
- extern void end_only_namespace_names            PARAMS ((void));
  extern tree namespace_ancestor			PARAMS ((tree, tree));
  extern tree unqualified_namespace_lookup	PARAMS ((tree, int, tree *));
  extern tree check_for_out_of_scope_variable     (tree);
  extern bool lookup_using_namespace (tree, tree, tree, tree, int, tree *);
  extern bool qualified_lookup_using_namespace (tree, tree, tree, int);
--- 3733,3743 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.977
diff -c -5 -p -r1.977 decl.c
*** cp/decl.c	31 Dec 2002 18:58:05 -0000	1.977
--- cp/decl.c	1 Jan 2003 02:40:27 -0000
*************** tree cp_global_trees[CPTI_MAX];
*** 205,217 ****
  /* Indicates that there is a type value in some namespace, although
     that is not necessarily in scope at the moment.  */
  
  static GTY(()) tree global_type_node;
  
- /* Expect only namespace names now.  */
- static int only_namespace_names;
- 
  /* Used only for jumps to as-yet undefined labels, since jumps to
     defined labels can have their validity checked immediately.  */
  
  struct named_label_use_list GTY(())
  {
--- 205,214 ----
*************** qualify_lookup (val, flags)
*** 5929,5942 ****
  {
    if (val == NULL_TREE)
      return val;
    if ((flags & LOOKUP_PREFER_NAMESPACES) && TREE_CODE (val) == NAMESPACE_DECL)
      return val;
!   if ((flags & LOOKUP_PREFER_TYPES)
!       && (TREE_CODE (val) == TYPE_DECL
! 	  || ((flags & LOOKUP_TEMPLATES_EXPECTED)
! 	      && DECL_CLASS_TEMPLATE_P (val))))
      return val;
    if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
      return NULL_TREE;
    return val;
  }
--- 5926,5936 ----
  {
    if (val == NULL_TREE)
      return val;
    if ((flags & LOOKUP_PREFER_NAMESPACES) && TREE_CODE (val) == NAMESPACE_DECL)
      return val;
!   if ((flags & LOOKUP_PREFER_TYPES) && TREE_CODE (val) == TYPE_DECL)
      return val;
    if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
      return NULL_TREE;
    return val;
  }
*************** lookup_name_real (tree name, 
*** 6103,6116 ****
  	}
  
        return NULL_TREE;
      }
  
-   /* Hack: copy flag set by parser, if set. */
-   if (only_namespace_names)
-     namespaces_only = 1;
- 
    flags |= lookup_flags (prefer_type, namespaces_only);
  
    /* First, look in non-namespace scopes.  */
  
    if (current_class_type == NULL_TREE)
--- 6097,6106 ----
*************** lookup_function_nonclass (name, args)
*** 6182,6199 ****
  {
    return lookup_arg_dependent (name, lookup_name_nonclass (name), args);
  }
  
  tree
- lookup_name_namespace_only (name)
-      tree name;
- {
-   /* type-or-namespace, nonclass, namespace_only */
-   return lookup_name_real (name, 1, 1, 1, LOOKUP_COMPLAIN);
- }
- 
- tree
  lookup_name (name, prefer_type)
       tree name;
       int prefer_type;
  {
    return lookup_name_real (name, prefer_type, 0, 0, LOOKUP_COMPLAIN);
--- 6172,6181 ----
*************** lookup_type_current_level (name)
*** 6265,6285 ****
      }
  
    return t;
  }
  
- void
- begin_only_namespace_names ()
- {
-   only_namespace_names = 1;
- }
- 
- void
- end_only_namespace_names ()
- {
-   only_namespace_names = 0;
- }
  
  /* Push the declarations of builtin types into the namespace.
     RID_INDEX is the index of the builtin type
     in the array RID_POINTERS.  NAME is the name used when looking
     up the builtin type.  TYPE is the _TYPE node for the builtin type.  */
--- 6247,6256 ----
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.10
diff -c -5 -p -r1.10 parser.c
*** cp/parser.c	31 Dec 2002 20:28:27 -0000	1.10
--- cp/parser.c	1 Jan 2003 02:40:29 -0000
*************** static void cp_parser_label_declaration
*** 1682,1692 ****
    PARAMS ((cp_parser *));
  
  /* Utility Routines */
  
  static tree cp_parser_lookup_name
!   PARAMS ((cp_parser *, tree, bool, bool, bool));
  static tree cp_parser_lookup_name_simple
    PARAMS ((cp_parser *, tree));
  static tree cp_parser_resolve_typename_type
    PARAMS ((cp_parser *, tree));
  static tree cp_parser_maybe_treat_template_as_class
--- 1682,1692 ----
    PARAMS ((cp_parser *));
  
  /* Utility Routines */
  
  static tree cp_parser_lookup_name
!   PARAMS ((cp_parser *, tree, bool, bool, bool, bool));
  static tree cp_parser_lookup_name_simple
    PARAMS ((cp_parser *, tree));
  static tree cp_parser_resolve_typename_type
    PARAMS ((cp_parser *, tree));
  static tree cp_parser_maybe_treat_template_as_class
*************** cp_parser_nested_name_specifier_opt (cp_
*** 3556,3565 ****
--- 3556,3574 ----
  		  else
  		    error ("`%D' is not a class-name or namespace-name",
  			   token->value);
  		  parser->scope = NULL_TREE;
  		  error_p = true;
+ 		  /* Treat this as a successful nested-name-specifier
+ 		     due to:
+ 
+ 		     [basic.lookup.qual]
+ 
+ 		     If the name found is not a class-name (clause
+ 		     _class_) or namespace-name (_namespace.def_), the
+ 		     program is ill-formed.  */
+ 		  success = true;
  		}
  	      cp_lexer_consume_token (parser->lexer);
  	    }
  	  break;
  	}
*************** cp_parser_nested_name_specifier (cp_pars
*** 3661,3671 ****
     TYPE_P is TRUE iff the next name should be taken as a class-name,
     even the same name is declared to be another entity in the same
     scope.
  
     Returns the class (TYPE_DECL) or namespace (NAMESPACE_DECL)
!    specified by the class-or-namespace-name.  */
  
  static tree
  cp_parser_class_or_namespace_name (cp_parser *parser, 
  				   bool typename_keyword_p,
  				   bool template_keyword_p,
--- 3670,3681 ----
     TYPE_P is TRUE iff the next name should be taken as a class-name,
     even the same name is declared to be another entity in the same
     scope.
  
     Returns the class (TYPE_DECL) or namespace (NAMESPACE_DECL)
!    specified by the class-or-namespace-name.  If neither is found the
!    ERROR_MARK_NODE is returned.  */
  
  static tree
  cp_parser_class_or_namespace_name (cp_parser *parser, 
  				   bool typename_keyword_p,
  				   bool template_keyword_p,
*************** cp_parser_class_or_namespace_name (cp_pa
*** 3674,3683 ****
--- 3684,3694 ----
  {
    tree saved_scope;
    tree saved_qualifying_scope;
    tree saved_object_scope;
    tree scope;
+   bool only_class_p;
  
    /* If the next token is the `template' keyword, we know that we are
       looking at a class-name.  */
    if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
      return cp_parser_class_name (parser, 
*************** cp_parser_class_or_namespace_name (cp_pa
*** 3691,3717 ****
       current PARSER->SCOPE since cp_parser_class_name will destroy
       it.  */
    saved_scope = parser->scope;
    saved_qualifying_scope = parser->qualifying_scope;
    saved_object_scope = parser->object_scope;
!   /* Try for a class-name first.  */
!   cp_parser_parse_tentatively (parser);
    scope = cp_parser_class_name (parser, 
  				typename_keyword_p,
  				template_keyword_p,
  				type_p,
  				/*check_access_p=*/true,
  				check_dependency_p,
  				/*class_head_p=*/false);
    /* If that didn't work, try for a namespace-name.  */
!   if (!cp_parser_parse_definitely (parser))
      {
        /* Restore the saved scope.  */
        parser->scope = saved_scope;
        parser->qualifying_scope = saved_qualifying_scope;
        parser->object_scope = saved_object_scope;
!       /* Now look for a namespace-name.  */
        scope = cp_parser_namespace_name (parser);
      }
  
    return scope;
  }
--- 3702,3737 ----
       current PARSER->SCOPE since cp_parser_class_name will destroy
       it.  */
    saved_scope = parser->scope;
    saved_qualifying_scope = parser->qualifying_scope;
    saved_object_scope = parser->object_scope;
!   /* Try for a class-name first.  If the SAVED_SCOPE is a type, then
!      there is no need to look for a namespace-name.  */
!   only_class_p = saved_scope && TYPE_P (saved_scope);
!   if (!only_class_p)
!     cp_parser_parse_tentatively (parser);
    scope = cp_parser_class_name (parser, 
  				typename_keyword_p,
  				template_keyword_p,
  				type_p,
  				/*check_access_p=*/true,
  				check_dependency_p,
  				/*class_head_p=*/false);
    /* If that didn't work, try for a namespace-name.  */
!   if (!only_class_p && !cp_parser_parse_definitely (parser))
      {
        /* Restore the saved scope.  */
        parser->scope = saved_scope;
        parser->qualifying_scope = saved_qualifying_scope;
        parser->object_scope = saved_object_scope;
!       /* If we are not looking at an identifier followed by the scope
! 	 resolution operator, then this is not part of a
! 	 nested-name-specifier.  (Note that this function is only used
! 	 to parse the components of a nested-name-specifier.)  */
!       if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)
! 	  || cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
! 	return error_mark_node;
        scope = cp_parser_namespace_name (parser);
      }
  
    return scope;
  }
*************** cp_parser_template_name (parser, templat
*** 8223,8232 ****
--- 8243,8253 ----
  
    /* Look up the name.  */
    decl = cp_parser_lookup_name (parser, identifier,
  				/*check_access=*/true,
  				/*is_type=*/false,
+ 				/*is_namespace=*/false,
  				check_dependency_p);
    decl = maybe_get_template_decl_from_type_decl (decl);
  
    /* If DECL is a template, then the name was a template-name.  */
    if (TREE_CODE (decl) == TEMPLATE_DECL)
*************** cp_parser_elaborated_type_specifier (par
*** 8964,8973 ****
--- 8985,8995 ----
  	     types, so we set IS_TYPE to TRUE when calling
  	     cp_parser_lookup_name.  */
  	  decl = cp_parser_lookup_name (parser, identifier, 
  					/*check_access=*/true,
  					/*is_type=*/true,
+ 					/*is_namespace=*/false,
  					/*check_dependency=*/true);
  	  decl = (cp_parser_maybe_treat_template_as_class 
  		  (decl, /*tag_name_p=*/is_friend));
  
  	  if (TREE_CODE (decl) != TYPE_DECL)
*************** cp_parser_namespace_name (parser)
*** 9191,9202 ****
    /* Get the name of the namespace.  */
    identifier = cp_parser_identifier (parser);
    if (identifier == error_mark_node)
      return error_mark_node;
  
!   /* Look up the identifier in the currently active scope.  */
!   namespace_decl = cp_parser_lookup_name_simple (parser, identifier);
    /* If it's not a namespace, issue an error.  */
    if (namespace_decl == error_mark_node
        || TREE_CODE (namespace_decl) != NAMESPACE_DECL)
      {
        cp_parser_error (parser, "expected namespace-name");
--- 9213,9245 ----
    /* Get the name of the namespace.  */
    identifier = cp_parser_identifier (parser);
    if (identifier == error_mark_node)
      return error_mark_node;
  
!   /* Look up the identifier in the currently active scope.  Look only
!      for namespaces, due to:
! 
!        [basic.lookup.udir]
! 
!        When looking up a namespace-name in a using-directive or alias
!        definition, only namespace names are considered.  
! 
!      And:
! 
!        [basic.lookup.qual]
! 
!        During the lookup of a name preceding the :: scope resolution
!        operator, object, function, and enumerator names are ignored.  
! 
!      (Note that cp_parser_class_or_namespace_name only calls this
!      function if the token after the name is the scope resolution
!      operator.)  */
!   namespace_decl = cp_parser_lookup_name (parser, identifier,
! 					  /*check_access=*/true,
! 					  /*is_type=*/false,
! 					  /*is_namespace=*/true,
! 					  /*check_dependency=*/true);
    /* If it's not a namespace, issue an error.  */
    if (namespace_decl == error_mark_node
        || TREE_CODE (namespace_decl) != NAMESPACE_DECL)
      {
        cp_parser_error (parser, "expected namespace-name");
*************** cp_parser_class_name (cp_parser *parser,
*** 11404,11413 ****
--- 11447,11457 ----
  	    type_p = true;
  	  /* Look up the name.  */
  	  decl = cp_parser_lookup_name (parser, identifier, 
  					check_access_p,
  					type_p,
+ 					/*is_namespace=*/false,
  					check_dependency_p);
  	}
      }
    else
      {
*************** cp_parser_label_declaration (parser)
*** 13266,13286 ****
     issued if the declaration is inaccessible.
  
     If IS_TYPE is TRUE, bindings that do not refer to types are
     ignored.
  
     If CHECK_DEPENDENCY is TRUE, names are not looked up in dependent
     types.  */
  
  static tree
! cp_parser_lookup_name (parser, name, check_access, is_type, 
! 		       check_dependency)
!      cp_parser *parser;
!      tree name;
!      bool check_access;
!      bool is_type;
!      bool check_dependency;
  {
    tree decl;
    tree object_type = parser->context->object_type;
  
    /* Now that we have looked up the name, the OBJECT_TYPE (if any) is
--- 13310,13328 ----
     issued if the declaration is inaccessible.
  
     If IS_TYPE is TRUE, bindings that do not refer to types are
     ignored.
  
+    If IS_NAMESPACE is TRUE, bindings that do not refer to namespaces
+    are ignored.
+ 
     If CHECK_DEPENDENCY is TRUE, names are not looked up in dependent
     types.  */
  
  static tree
! cp_parser_lookup_name (cp_parser *parser, tree name, bool check_access, 
! 		       bool is_type, bool is_namespace, bool check_dependency)
  {
    tree decl;
    tree object_type = parser->context->object_type;
  
    /* Now that we have looked up the name, the OBJECT_TYPE (if any) is
*************** cp_parser_lookup_name (parser, name, che
*** 13394,13414 ****
  	object_decl = lookup_member (object_type,
  				     name,
  				     /*protect=*/0, is_type);
        /* Look it up in the enclosing context, too.  */
        decl = lookup_name_real (name, is_type, /*nonclass=*/0, 
! 			       /*namespaces_only=*/0, 
  			       /*flags=*/0);
        parser->object_scope = object_type;
        parser->qualifying_scope = NULL_TREE;
        if (object_decl)
  	decl = object_decl;
      }
    else
      {
        decl = lookup_name_real (name, is_type, /*nonclass=*/0, 
! 			       /*namespaces_only=*/0, 
  			       /*flags=*/0);
        parser->qualifying_scope = NULL_TREE;
        parser->object_scope = NULL_TREE;
      }
  
--- 13436,13456 ----
  	object_decl = lookup_member (object_type,
  				     name,
  				     /*protect=*/0, is_type);
        /* Look it up in the enclosing context, too.  */
        decl = lookup_name_real (name, is_type, /*nonclass=*/0, 
! 			       is_namespace,
  			       /*flags=*/0);
        parser->object_scope = object_type;
        parser->qualifying_scope = NULL_TREE;
        if (object_decl)
  	decl = object_decl;
      }
    else
      {
        decl = lookup_name_real (name, is_type, /*nonclass=*/0, 
! 			       is_namespace,
  			       /*flags=*/0);
        parser->qualifying_scope = NULL_TREE;
        parser->object_scope = NULL_TREE;
      }
  
*************** cp_parser_lookup_name_simple (parser, na
*** 13479,13489 ****
       cp_parser *parser;
       tree name;
  {
    return cp_parser_lookup_name (parser, name, 
  				/*check_access=*/true,
! 				/*is_type=*/false, 
  				/*check_dependency=*/true);
  }
  
  /* TYPE is a TYPENAME_TYPE.  Returns the ordinary TYPE to which the
     TYPENAME_TYPE corresponds.  Note that this function peers inside
--- 13521,13532 ----
       cp_parser *parser;
       tree name;
  {
    return cp_parser_lookup_name (parser, name, 
  				/*check_access=*/true,
! 				/*is_type=*/false,
! 				/*is_namespace=*/false,
  				/*check_dependency=*/true);
  }
  
  /* TYPE is a TYPENAME_TYPE.  Returns the ordinary TYPE to which the
     TYPENAME_TYPE corresponds.  Note that this function peers inside
Index: testsuite/g++.dg/parse/namespace1.C
===================================================================
RCS file: testsuite/g++.dg/parse/namespace1.C
diff -N testsuite/g++.dg/parse/namespace1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/namespace1.C	1 Jan 2003 02:40:30 -0000
***************
*** 0 ****
--- 1,7 ----
+ namespace foo {
+ void baz(int);
+ }
+ 
+ int bar(int foo) {
+   foo::baz (3);
+ }



More information about the Gcc-patches mailing list