OSDN Git Service

PR c++/42447
[pf3gnuchains/gcc-fork.git] / gcc / cp / pt.c
index c3b0f0e..d5342a1 100644 (file)
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "obstack.h"
 #include "tree.h"
+#include "intl.h"
 #include "pointer-set.h"
 #include "flags.h"
 #include "c-common.h"
@@ -189,7 +190,8 @@ static tree tsubst_copy     (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_decl (tree, tree, tsubst_flags_t);
 static void perform_typedefs_access_check (tree tmpl, tree targs);
-static void append_type_to_template_for_access_check_1 (tree, tree, tree);
+static void append_type_to_template_for_access_check_1 (tree, tree, tree,
+                                                       location_t);
 static hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
@@ -286,6 +288,17 @@ finish_member_template_decl (tree decl)
   return error_mark_node;
 }
 
+/* Create a template info node.  */
+
+tree
+build_template_info (tree template_decl, tree template_args)
+{
+  tree result = make_node (TEMPLATE_INFO);
+  TI_TEMPLATE (result) = template_decl;
+  TI_ARGS (result) = template_args;
+  return result;
+}
+
 /* Return the template info node corresponding to T, whatever T is.  */
 
 tree
@@ -729,6 +742,12 @@ check_specialization_namespace (tree tmpl)
      function, member class or static data member of a class template
      shall be declared in the namespace of which the class template is
      a member.  */
+  if (current_scope() != DECL_CONTEXT (tmpl)
+      && !at_namespace_scope_p ())
+    {
+      error ("specialization of %qD must appear at namespace scope", tmpl);
+      return false;
+    }
   if (is_associated_namespace (current_namespace, tpl_ns))
     /* Same or super-using namespace.  */
     return true;
@@ -1444,6 +1463,11 @@ iterative_hash_template_arg (tree arg, hashval_t val)
   if (!TYPE_P (arg))
     STRIP_NOPS (arg);
 
+  if (TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
+    /* We can get one of these when re-hashing a previous entry in the middle
+       of substituting into a pack expansion.  Just look through it.  */
+    arg = ARGUMENT_PACK_SELECT_FROM_PACK (arg);
+
   code = TREE_CODE (arg);
   tclass = TREE_CODE_CLASS (code);
 
@@ -1469,11 +1493,6 @@ iterative_hash_template_arg (tree arg, hashval_t val)
     case EXPR_PACK_EXPANSION:
       return iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val);
 
-    case ARGUMENT_PACK_SELECT:
-      /* We can get one of these when re-hashing a previous entry in the middle
-         of substituting into a pack expansion.  Just look through it...  */
-      arg = ARGUMENT_PACK_SELECT_FROM_PACK (arg);
-      /* ...and fall through.  */
     case TYPE_ARGUMENT_PACK:
     case NONTYPE_ARGUMENT_PACK:
       return iterative_hash_template_arg (ARGUMENT_PACK_ARGS (arg), val);
@@ -1534,6 +1553,13 @@ iterative_hash_template_arg (tree arg, hashval_t val)
       val = iterative_hash_object (code, val);
       return iterative_hash_template_arg (TREE_OPERAND (arg, 2), val);
 
+    case ARRAY_TYPE:
+      /* layout_type sets structural equality for arrays of
+        incomplete type, so we can't rely on the canonical type
+        for hashing.  */
+      val = iterative_hash_template_arg (TREE_TYPE (arg), val);
+      return iterative_hash_template_arg (TYPE_DOMAIN (arg), val);
+
     default:
       switch (tclass)
        {
@@ -1634,32 +1660,65 @@ explicit_class_specialization_p (tree type)
   return !uses_template_parms (CLASSTYPE_TI_ARGS (type));
 }
 
-/* Print the list of candidate FNS in an error message.  */
+/* Print the list of functions at FNS, going through all the overloads
+   for each element of the list.  Alternatively, FNS can not be a
+   TREE_LIST, in which case it will be printed together with all the
+   overloads.
 
-void
-print_candidates (tree fns)
+   MORE and *STR should respectively be FALSE and NULL when the function
+   is called from the outside.  They are used internally on recursive
+   calls.  print_candidates manages the two parameters and leaves NULL
+   in *STR when it ends.  */
+
+static void
+print_candidates_1 (tree fns, bool more, const char **str)
 {
-  tree fn;
-  tree f;
+  tree fn, fn2;
+  char *spaces = NULL;
+
+  for (fn = fns; fn; fn = OVL_NEXT (fn))
+    if (TREE_CODE (fn) == TREE_LIST)
+      {
+        gcc_assert (!OVL_NEXT (fn) && !is_overloaded_fn (fn));
+        for (fn2 = fn; fn2 != NULL_TREE; fn2 = TREE_CHAIN (fn2))
+          print_candidates_1 (TREE_VALUE (fn2),
+                              TREE_CHAIN (fn2) || more, str);
+      }
+    else
+      {
+        if (!*str)
+          {
+            /* Pick the prefix string.  */
+            if (!more && !OVL_NEXT (fns))
+              {
+                error ("candidate is: %+#D", OVL_CURRENT (fn));
+                continue;
+              }
 
-  const char *str = "candidates are:";
+            *str = _("candidates are:");
+            spaces = get_spaces (*str);
+          }
+        error ("%s %+#D", *str, OVL_CURRENT (fn));
+        *str = spaces ? spaces : *str;
+      }
 
-  if (is_overloaded_fn (fns))
+  if (!more)
     {
-      for (f = fns; f; f = OVL_NEXT (f))
-       {
-         error ("%s %+#D", str, OVL_CURRENT (f));
-         str = "               ";
-       }
-    }
-  else for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn))
-    {
-      for (f = TREE_VALUE (fn); f; f = OVL_NEXT (f))
-       error ("%s %+#D", str, OVL_CURRENT (f));
-      str = "               ";
+      free (spaces);
+      *str = NULL;
     }
 }
 
+/* Print the list of candidate FNS in an error message.  */
+
+void
+print_candidates (tree fns)
+{
+  const char *str = NULL;
+  print_candidates_1 (fns, false, &str);
+  gcc_assert (str == NULL);
+}
+
 /* Returns the template (one of the functions given by TEMPLATE_ID)
    which can be specialized to match the indicated DECL with the
    explicit template args given in TEMPLATE_ID.  The DECL may be
@@ -1933,6 +1992,10 @@ determine_specialization (tree template_id,
     {
       error ("template-id %qD for %q+D does not match any template "
             "declaration", template_id, decl);
+      if (header_count && header_count != template_count + 1)
+       inform (input_location, "saw %d %<template<>%>, need %d for "
+               "specializing a member function template",
+               header_count, template_count + 1);
       return error_mark_node;
     }
   else if ((templates && TREE_CHAIN (templates))
@@ -2492,7 +2555,7 @@ check_explicit_specialization (tree declarator,
            }
 
          /* Set up the DECL_TEMPLATE_INFO for DECL.  */
-         DECL_TEMPLATE_INFO (decl) = tree_cons (tmpl, targs, NULL_TREE);
+         DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs);
 
          /* Inherit default function arguments from the template
             DECL is specializing.  */
@@ -2680,15 +2743,13 @@ get_function_template_decl (const_tree primary_func_tmpl_inst)
 bool
 function_parameter_expanded_from_pack_p (tree param_decl, tree pack)
 {
-    if (DECL_ARTIFICIAL (param_decl)
-       || !function_parameter_pack_p (pack))
-      return false;
-
-    gcc_assert (DECL_NAME (param_decl) && DECL_NAME (pack));
+  if (DECL_ARTIFICIAL (param_decl)
+      || !function_parameter_pack_p (pack))
+    return false;
 
-    /* The parameter pack and its pack arguments have the same
-       DECL_PARM_INDEX.  */
-    return DECL_PARM_INDEX (pack) == DECL_PARM_INDEX (param_decl);
+  /* The parameter pack and its pack arguments have the same
+     DECL_PARM_INDEX.  */
+  return DECL_PARM_INDEX (pack) == DECL_PARM_INDEX (param_decl);
 }
 
 /* Determine whether ARGS describes a variadic template args list,
@@ -2900,7 +2961,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
     case UNION_TYPE:
     case ENUMERAL_TYPE:
       if (TYPE_TEMPLATE_INFO (t))
-       cp_walk_tree (&TREE_VALUE (TYPE_TEMPLATE_INFO (t)), 
+       cp_walk_tree (&TI_ARGS (TYPE_TEMPLATE_INFO (t)),
                      &find_parameter_packs_r, ppd, ppd->visited);
 
       *walk_subtrees = 0;
@@ -3302,7 +3363,8 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args,
 {
   if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
       || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
-         != TEMPLATE_PARM_LEVEL (index) - levels))
+         != TEMPLATE_PARM_LEVEL (index) - levels)
+      || !same_type_p (type, TREE_TYPE (TEMPLATE_PARM_DESCENDANTS (index))))
     {
       tree orig_decl = TEMPLATE_PARM_DECL (index);
       tree decl, t;
@@ -3795,12 +3857,11 @@ process_partial_specialization (tree decl)
                   || (!packed_args && i < nargs - 1))
                 {
                   if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
-                    error ("parameter pack argument %qE must be at the end of the template argument list", arg);
+                    error ("parameter pack argument %qE must be at the "
+                          "end of the template argument list", arg);
                   else
-                    error ("parameter pack argument %qT must be at the end of the template argument list", arg);
-
-                 if (packed_args)
-                   TREE_VEC_ELT (packed_args, j) = error_mark_node;
+                    error ("parameter pack argument %qT must be at the "
+                          "end of the template argument list", arg);
                 }
             }
 
@@ -4352,7 +4413,7 @@ push_template_decl_real (tree decl, bool is_friend)
          DECL_TI_TEMPLATE (decl) = new_tmpl;
          SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl);
          DECL_TEMPLATE_INFO (new_tmpl)
-           = tree_cons (tmpl, args, NULL_TREE);
+           = build_template_info (tmpl, args);
 
          register_specialization (new_tmpl,
                                   most_general_template (tmpl),
@@ -4461,6 +4522,9 @@ template arguments to %qD do not match original template %qD",
          tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
          if (TREE_CODE (parm) == TEMPLATE_DECL)
            DECL_CONTEXT (parm) = tmpl;
+
+         if (TREE_CODE (TREE_TYPE (parm)) == TEMPLATE_TYPE_PARM)
+           DECL_CONTEXT (TYPE_NAME (TREE_TYPE (parm))) = tmpl;
        }
     }
 
@@ -4471,7 +4535,7 @@ template arguments to %qD do not match original template %qD",
   if (DECL_TEMPLATE_INFO (tmpl))
     args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args);
 
-  info = tree_cons (tmpl, args, NULL_TREE);
+  info = build_template_info (tmpl, args);
 
   if (DECL_IMPLICIT_TYPEDEF_P (decl))
     SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
@@ -5542,6 +5606,15 @@ convert_template_argument (tree parm,
        val = error_mark_node;
       else if (val == error_mark_node && (complain & tf_error))
        error ("could not convert template argument %qE to %qT",  orig_arg, t);
+
+      if (TREE_CODE (val) == SCOPE_REF)
+       {
+         /* Strip typedefs from the SCOPE_REF.  */
+         tree type = strip_typedefs (TREE_TYPE (val));
+         tree scope = strip_typedefs (TREE_OPERAND (val, 0));
+         val = build_qualified_name (type, scope, TREE_OPERAND (val, 1),
+                                     QUALIFIED_NAME_IS_TEMPLATE (val));
+       }
     }
 
   return val;
@@ -6449,7 +6522,7 @@ lookup_template_class (tree d1,
          found = CLASSTYPE_TI_TEMPLATE (found);
        }
 
-      SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE));
+      SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
 
       elt.spec = t;
       slot = (spec_entry **) htab_find_slot_with_hash (type_specializations,
@@ -6525,7 +6598,7 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
     case ENUMERAL_TYPE:
       if (!TYPE_TEMPLATE_INFO (t))
        *walk_subtrees = 0;
-      else if (for_each_template_parm (TREE_VALUE (TYPE_TEMPLATE_INFO (t)),
+      else if (for_each_template_parm (TI_ARGS (TYPE_TEMPLATE_INFO (t)),
                                       fn, data, pfd->visited, 
                                       pfd->include_nondeduced_p))
        return error_mark_node;
@@ -7381,17 +7454,24 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
 static void
 perform_typedefs_access_check (tree tmpl, tree targs)
 {
-  tree t;
+  location_t saved_location;
+  int i;
+  qualified_typedef_usage_t *iter;
 
   if (!tmpl
       || (!CLASS_TYPE_P (tmpl)
          && TREE_CODE (tmpl) != FUNCTION_DECL))
     return;
 
-  for (t = get_types_needing_access_check (tmpl); t; t = TREE_CHAIN (t))
+  saved_location = input_location;
+  for (i = 0;
+       VEC_iterate (qualified_typedef_usage_t,
+                   get_types_needing_access_check (tmpl),
+                   i, iter);
+       ++i)
     {
-      tree type_decl = TREE_PURPOSE (t);
-      tree type_scope = TREE_VALUE (t);
+      tree type_decl = iter->typedef_decl;
+      tree type_scope = iter->context;
 
       if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
        continue;
@@ -7401,9 +7481,13 @@ perform_typedefs_access_check (tree tmpl, tree targs)
       if (uses_template_parms (type_scope))
        type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
 
+      /* Make access check error messages point to the location
+         of the use of the typedef.  */
+      input_location = iter->locus;
       perform_or_defer_access_check (TYPE_BINFO (type_scope),
                                     type_decl, type_decl);
     }
+    input_location = saved_location;
 }
 
 tree
@@ -7967,7 +8051,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 {
   tree pattern;
   tree pack, packs = NULL_TREE, unsubstituted_packs = NULL_TREE;
-  tree first_arg_pack; int i, len = -1;
+  int i, len = -1;
   tree result;
   int incomplete = 0;
   bool very_local_specializations = false;
@@ -8051,10 +8135,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
             incomplete = 1;
 
           if (len < 0)
-            {
-              len = my_len;
-              first_arg_pack = arg_pack;
-            }
+           len = my_len;
           else if (len != my_len)
             {
              if (incomplete)
@@ -8655,7 +8736,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
        gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
        TREE_CHAIN (r) = NULL_TREE;
 
-       DECL_TEMPLATE_INFO (r) = build_tree_list (t, args);
+       DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
 
        if (TREE_CODE (decl) == TYPE_DECL)
          {
@@ -8884,7 +8965,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
        if (gen_tmpl)
          {
            DECL_TEMPLATE_INFO (r)
-             = tree_cons (gen_tmpl, argvec, NULL_TREE);
+             = build_template_info (gen_tmpl, argvec);
            SET_DECL_IMPLICIT_INSTANTIATION (r);
            register_specialization (r, gen_tmpl, argvec, false, hash);
 
@@ -9207,7 +9288,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
        /* Create a new node for the specialization we need.  */
        r = copy_decl (t);
        if (type == NULL_TREE)
-         type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+         {
+           if (is_typedef_decl (t))
+             type = DECL_ORIGINAL_TYPE (t);
+           else
+             type = TREE_TYPE (t);
+           type = tsubst (type, args, complain, in_decl);
+         }
        if (TREE_CODE (r) == VAR_DECL)
          {
            /* Even if the original location is out of scope, the
@@ -9278,16 +9365,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
              }
            determine_visibility (r);
          }
-       /* Preserve a typedef that names a type.  */
-       else if (TREE_CODE (r) == TYPE_DECL
-                && DECL_ORIGINAL_TYPE (t)
-                && type != error_mark_node)
-         {
-           DECL_ORIGINAL_TYPE (r) = tsubst (DECL_ORIGINAL_TYPE (t),
-                                            args, complain, in_decl);
-           TREE_TYPE (r) = type = build_variant_type_copy (type);
-           TYPE_NAME (type) = r;
-         }
 
        if (!local_p)
          {
@@ -9298,7 +9375,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
            DECL_EXTERNAL (r) = 1;
 
            register_specialization (r, gen_tmpl, argvec, false, hash);
-           DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
+           DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec);
            SET_DECL_IMPLICIT_INSTANTIATION (r);
          }
        else if (cp_unevaluated_operand)
@@ -9325,6 +9402,14 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
        apply_late_template_attributes (&r, DECL_ATTRIBUTES (r),
                                        (int) ATTR_FLAG_TYPE_IN_PLACE,
                                        args, complain, in_decl);
+
+       /* Preserve a typedef that names a type.  */
+       if (is_typedef_decl (r))
+         {
+           DECL_ORIGINAL_TYPE (r) = NULL_TREE;
+           set_underlying_type (r);
+         }
+
        layout_decl (r, 0);
       }
       break;
@@ -9907,7 +9992,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
                      return error_mark_node;
 
                    TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r)
-                     = tree_cons (TYPE_TI_TEMPLATE (t), argvec, NULL_TREE);
+                     = build_template_info (TYPE_TI_TEMPLATE (t), argvec);
                  }
              }
            break;
@@ -10004,10 +10089,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
              {
                if (TREE_CODE (type) == VOID_TYPE)
                  error ("forming reference to void");
-               else
-                 error ("forming %s to reference type %qT",
-                        (code == POINTER_TYPE) ? "pointer" : "reference",
-                        type);
+               else if (code == POINTER_TYPE)
+                 error ("forming pointer to reference type %qT", type);
+               else
+                 error ("forming reference to reference type %qT", type);
                last_loc = input_location;
              }
 
@@ -11790,7 +11875,7 @@ tsubst_copy_and_build (tree t,
              r = convert_from_reference (r);
          }
        else
-         r = build_x_indirect_ref (r, "unary *", complain);
+         r = build_x_indirect_ref (r, RO_UNARY_STAR, complain);
        return r;
       }
 
@@ -12511,6 +12596,11 @@ tsubst_copy_and_build (tree t,
        stmt_expr = finish_stmt_expr (stmt_expr, false);
        cur_stmt_expr = old_stmt_expr;
 
+       /* If the resulting list of expression statement is empty,
+          fold it further into void_zero_node.  */
+       if (empty_expr_stmt_p (stmt_expr))
+         stmt_expr = void_zero_node;
+
        return stmt_expr;
       }
 
@@ -15709,13 +15799,16 @@ most_specialized_class (tree type, tree tmpl)
 
   if (ambiguous_p)
     {
-      const char *str = "candidates are:";
+      const char *str;
+      char *spaces = NULL;
       error ("ambiguous class template instantiation for %q#T", type);
+      str = TREE_CHAIN (list) ? _("candidates are:") : _("candidate is:");
       for (t = list; t; t = TREE_CHAIN (t))
-       {
-         error ("%s %+#T", str, TREE_TYPE (t));
-         str = "               ";
-       }
+        {
+          error ("%s %+#T", spaces ? spaces : str, TREE_TYPE (t));
+          spaces = spaces ? spaces : get_spaces (str);
+        }
+      free (spaces);
       return error_mark_node;
     }
 
@@ -18080,28 +18173,29 @@ type_uses_auto (tree type)
   return NULL_TREE;
 }
 
-/* For a given template T, return the list of typedefs referenced
+/* For a given template T, return the vector of typedefs referenced
    in T for which access check is needed at T instantiation time.
    T is either  a FUNCTION_DECL or a RECORD_TYPE.
    Those typedefs were added to T by the function
    append_type_to_template_for_access_check.  */
 
-tree
+VEC(qualified_typedef_usage_t,gc)*
 get_types_needing_access_check (tree t)
 {
-  tree ti, result = NULL_TREE;
+  tree ti;
+  VEC(qualified_typedef_usage_t,gc) *result = NULL;
 
   if (!t || t == error_mark_node)
-    return t;
+    return NULL;
 
   if (!(ti = get_template_info (t)))
-    return NULL_TREE;
+    return NULL;
 
   if (CLASS_TYPE_P (t)
       || TREE_CODE (t) == FUNCTION_DECL)
     {
       if (!TI_TEMPLATE (ti))
-       return NULL_TREE;
+       return NULL;
 
       result = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
     }
@@ -18115,6 +18209,7 @@ get_types_needing_access_check (tree t)
    T is either a FUNCTION_DECL or a RECORD_TYPE.
    TYPE_DECL is a TYPE_DECL node representing a typedef.
    SCOPE is the scope through which TYPE_DECL is accessed.
+   LOCATION is the location of the usage point of TYPE_DECL.
 
    This function is a subroutine of
    append_type_to_template_for_access_check.  */
@@ -18122,8 +18217,10 @@ get_types_needing_access_check (tree t)
 static void
 append_type_to_template_for_access_check_1 (tree t,
                                            tree type_decl,
-                                           tree scope)
+                                           tree scope,
+                                           location_t location)
 {
+  qualified_typedef_usage_t typedef_usage;
   tree ti;
 
   if (!t || t == error_mark_node)
@@ -18140,14 +18237,20 @@ append_type_to_template_for_access_check_1 (tree t,
 
   gcc_assert (TI_TEMPLATE (ti));
 
-  TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti) =
-    tree_cons (type_decl, scope, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti));
+  typedef_usage.typedef_decl = type_decl;
+  typedef_usage.context = scope;
+  typedef_usage.locus = location;
+
+  VEC_safe_push (qualified_typedef_usage_t, gc,
+                TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti),
+                &typedef_usage);
 }
 
 /* Append TYPE_DECL to the template TEMPL.
    TEMPL is either a class type, a FUNCTION_DECL or a a TEMPLATE_DECL.
    At TEMPL instanciation time, TYPE_DECL will be checked to see
    if it can be accessed through SCOPE.
+   LOCATION is the location of the usage point of TYPE_DECL.
 
    e.g. consider the following code snippet:
 
@@ -18158,7 +18261,7 @@ append_type_to_template_for_access_check_1 (tree t,
 
      template<class U> struct S
      {
-       C::myint mi;
+       C::myint mi; // <-- usage point of the typedef C::myint
      };
 
      S<char> s;
@@ -18175,25 +18278,25 @@ append_type_to_template_for_access_check_1 (tree t,
 void
 append_type_to_template_for_access_check (tree templ,
                                           tree type_decl,
-                                         tree scope)
+                                         tree scope,
+                                         location_t location)
 {
-  tree node;
+  qualified_typedef_usage_t *iter;
+  int i;
 
   gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
 
   /* Make sure we don't append the type to the template twice.  */
-  for (node = get_types_needing_access_check (templ);
-       node;
-       node = TREE_CHAIN (node))
-    {
-      tree decl = TREE_PURPOSE (node);
-      tree type_scope = TREE_VALUE (node);
-
-      if (decl == type_decl && type_scope == scope)
-       return;
-    }
+  for (i = 0;
+       VEC_iterate (qualified_typedef_usage_t,
+                   get_types_needing_access_check (templ),
+                   i, iter);
+       ++i)
+    if (iter->typedef_decl == type_decl && scope == iter->context)
+      return;
 
-  append_type_to_template_for_access_check_1 (templ, type_decl, scope);
+  append_type_to_template_for_access_check_1 (templ, type_decl,
+                                             scope, location);
 }
 
 /* Set up the hash tables for template instantiations.  */