decl.c (warn_about_implicit_typename_lookup): New function.
authorMark Mitchell <mark@codesourcery.com>
Fri, 16 Apr 1999 00:15:26 +0000 (00:15 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 16 Apr 1999 00:15:26 +0000 (00:15 +0000)
* decl.c (warn_about_implicit_typename_lookup): New function.
(lookup_name_real): Use it.  Rework handling of implicit typename
extension.

From-SVN: r26487

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/g++.old-deja/g++.pt/typename18.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/typename19.C [new file with mode: 0644]

index cdcb7b574578fb16d99bf5c57f6f219b9cba940a..8f6159813ee0be21bd9fe945c04158118815bb54 100644 (file)
@@ -1,3 +1,9 @@
+1999-04-16  Mark Mitchell  <mark@codesourcery.com>
+
+       * decl.c (warn_about_implicit_typename_lookup): New function.
+       (lookup_name_real): Use it.  Rework handling of implicit typename
+       extension.
+
 1999-04-15  Mark Mitchell  <mark@codesourcery.com>
 
        * cp-tree.h (lookup_nested_field): Remove.
index 163c3d75ef7e272e8ba19bfea353d6ec5386c9b3..fe30586454d2d2d5b30ae67ea1e86ab4c77e7425 100644 (file)
@@ -192,6 +192,7 @@ static const char *tag_name PROTO((enum tag_types code));
 static void find_class_binding_level PROTO((void));
 static struct binding_level *innermost_nonclass_level PROTO((void));
 static tree poplevel_class PROTO((void));
+static void warn_about_implicit_typename_lookup PROTO((tree, tree));
 
 #if defined (DEBUG_CP_BINDING_LEVELS)
 static void indent PROTO((void));
@@ -5526,6 +5527,32 @@ qualify_lookup (val, flags)
   return val;
 }
 
+/* Any other BINDING overrides an implicit TYPENAME.  Warn about
+   that.  */
+
+static void
+warn_about_implicit_typename_lookup (typename, binding)
+     tree typename;
+     tree binding;
+{
+  tree subtype = TREE_TYPE (TREE_TYPE (typename));
+  tree name = DECL_NAME (typename);
+
+  if (! (TREE_CODE (binding) == TEMPLATE_DECL
+        && CLASSTYPE_TEMPLATE_INFO (subtype)
+        && CLASSTYPE_TI_TEMPLATE (subtype) == binding)
+      && ! (TREE_CODE (binding) == TYPE_DECL
+           && same_type_p (TREE_TYPE (binding), subtype)))
+    {
+      cp_warning ("lookup of `%D' finds `%#D'", 
+                 name, binding);
+      cp_warning ("  instead of `%D' from dependent base class",
+                 typename);
+      cp_warning ("  (use `typename %T::%D' if that's what you meant)",
+                 constructor_name (current_class_type), name);
+    }
+}
+
 /* Look up NAME in the current binding level and its superiors in the
    namespace of variables, functions and typedefs.  Return a ..._DECL
    node of some kind representing its definition if there is only one
@@ -5545,10 +5572,12 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
      tree name;
      int prefer_type, nonclass, namespaces_only;
 {
-  register tree val;
+  tree t;
+  tree val = NULL_TREE;
   int yylex = 0;
   tree from_obj = NULL_TREE;
   int flags;
+  int val_is_implicit_typename = 0;
 
   /* Hack: copy flag set by parser, if set. */
   if (only_namespace_names)
@@ -5623,67 +5652,49 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
     }
 
   /* First, look in non-namespace scopes.  */
-  for (val = IDENTIFIER_BINDING (name); val; val = TREE_CHAIN (val))
+  for (t = IDENTIFIER_BINDING (name); t; t = TREE_CHAIN (t))
     {
-      if (!LOCAL_BINDING_P (val) && nonclass)
+      tree binding;
+
+      if (!LOCAL_BINDING_P (t) && nonclass)
        /* We're not looking for class-scoped bindings, so keep going.  */
        continue;
       
       /* If this is the kind of thing we're looking for, we're done.  */
-      if (qualify_lookup (BINDING_VALUE (val), flags))
-       {
-         val = BINDING_VALUE (val);
-         break;
-       }
+      if (qualify_lookup (BINDING_VALUE (t), flags))
+       binding = BINDING_VALUE (t);
       else if ((flags & LOOKUP_PREFER_TYPES) 
-              && qualify_lookup (BINDING_TYPE (val), flags))
-       {
-         val = BINDING_TYPE (val);
-         break;
+              && qualify_lookup (BINDING_TYPE (t), flags))
+       binding = BINDING_TYPE (t);
+      else
+       binding = NULL_TREE;
+
+      if (binding
+         && (!val || !(TREE_CODE (binding) == TYPE_DECL
+                       && IMPLICIT_TYPENAME_P (TREE_TYPE (binding)))))
+       {
+         if (val_is_implicit_typename && !yylex)
+           warn_about_implicit_typename_lookup (val, binding);
+         val = binding;
+         val_is_implicit_typename 
+           = (TREE_CODE (val) == TYPE_DECL
+              && IMPLICIT_TYPENAME_P (TREE_TYPE (val)));
+         if (!val_is_implicit_typename)
+           break;
        }
     }
 
-  /* If we found a type from a dependent base class (using the
-     implicit typename extension) make sure that there's not some
-     global name which should be chosen instead.  */
-  if (val && TREE_CODE (val) == TYPE_DECL
-      && IMPLICIT_TYPENAME_P (TREE_TYPE (val)))
+  /* Now lookup in namespace scopes.  */
+  if (!val || val_is_implicit_typename)
     {
-      tree global_val;
-
-      /* Any other name takes precedence over an implicit typename.  Warn the
-        user about this potentially confusing lookup.  */
-      global_val = unqualified_namespace_lookup (name, flags);
-
-      if (global_val)
+      t = unqualified_namespace_lookup (name, flags);
+      if (t)
        {
-         tree subtype;
-
-         /* Only warn when not lexing; we don't want to warn if they
-            use this name as a declarator.  */
-         subtype = TREE_TYPE (TREE_TYPE (val));
-         if (! yylex
-             && ! (TREE_CODE (global_val) == TEMPLATE_DECL
-                   && CLASSTYPE_TEMPLATE_INFO (subtype)
-                   && CLASSTYPE_TI_TEMPLATE (subtype) == global_val)
-             && ! (TREE_CODE (global_val) == TYPE_DECL
-                   && same_type_p (TREE_TYPE (global_val), subtype)))
-           {
-             cp_warning ("lookup of `%D' finds `%#D'", name, global_val);
-             cp_warning ("  instead of `%D' from dependent base class",
-                         val);
-             cp_warning ("  (use `typename %T::%D' if that's what you meant)",
-                         constructor_name (current_class_type), name);
-           }
-
-         /* Use the global value instead of the implicit typename.  */
-         val = global_val;
+         if (val_is_implicit_typename && !yylex)
+           warn_about_implicit_typename_lookup (val, t);
+         val = t;
        }
     }
-  else if (!val)
-    /* No local, or class-scoped binding.  Look for a namespace-scope
-       declaration.  */
-    val = unqualified_namespace_lookup (name, flags);
 
  done:
   if (val)
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename18.C b/gcc/testsuite/g++.old-deja/g++.pt/typename18.C
new file mode 100644 (file)
index 0000000..ed423e7
--- /dev/null
@@ -0,0 +1,21 @@
+// Build don't link:
+// Special g++ Options:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+void X();
+
+template <class T>
+struct J {
+  typedef T X;
+};
+
+template <class T>
+struct S {
+  typedef T X;
+
+  struct I : public J<X> {
+    static X* f();
+  };
+};
+
+S<int> si;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename19.C b/gcc/testsuite/g++.old-deja/g++.pt/typename19.C
new file mode 100644 (file)
index 0000000..be93a98
--- /dev/null
@@ -0,0 +1,26 @@
+// Special g++ Options:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+template <class T>
+struct O {
+  typedef char X;
+};
+
+template <class T>
+struct S {
+  typedef double X;
+
+  template <class U>
+  struct I : public O<U> {
+    static X x; // WARNING - lookup finds S<T>::X
+  };
+};
+
+template <class T>
+template <class U>
+typename S<T>::X S<T>::I<U>::x;
+
+int main()
+{
+  return sizeof (S<int>::I<double>::x) == 1;
+}