Hi,

in this relatively serious ICE on invalid regression (we don't emit any message before ICEing) make_typename_type, called by strip_typedefs, returns error_mark_node which then isn't handled by typedef_variant_p. Indeed, Jakub noticed that the same in principle can happen when strip_typedefs calls finish_decltype_type. make_typename_type is passed tf_none therefore cannot emit the diagnostic we want before the ICE anyway, thus it seems to me that we also have one of those well known issues about not propagating a tusbst_flags_t flag: canonicalize_type_argument (and canonicalize_expr_argument) get a tusbst_flags_t but doesn't propagate it to strip_typedefs (and strip_typedefs_expr).

Implementing the straightforward set of changes, consistently for strip_typedefs, strip_typedefs_expr and the related functions plus checking the return values of make_typename_type and finish_decltype_type for error_mark_node (only make_typename_type would be enough for the testcase at issue) appears to solve the problem without introducing regressions. Does that make sense?

Thanks,
Paolo.

/////////////////////////////
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h        (revision 244803)
+++ cp/cp-tree.h        (working copy)
@@ -6597,8 +6597,10 @@ extern bool class_tmpl_impl_spec_p               
(const_tree);
 extern int zero_init_p                         (const_tree);
 extern bool check_abi_tag_redeclaration                (const_tree, 
const_tree, const_tree);
 extern bool check_abi_tag_args                 (tree, tree);
-extern tree strip_typedefs                     (tree, bool * = NULL);
-extern tree strip_typedefs_expr                        (tree, bool * = NULL);
+extern tree strip_typedefs                     (tree, tsubst_flags_t,
+                                                bool * = NULL);
+extern tree strip_typedefs_expr                        (tree, tsubst_flags_t,
+                                                bool * = NULL);
 extern tree copy_binfo                         (tree, tree, tree,
                                                 tree *, int);
 extern int member_p                            (const_tree);
Index: cp/error.c
===================================================================
--- cp/error.c  (revision 244803)
+++ cp/error.c  (working copy)
@@ -354,7 +354,7 @@ dump_template_bindings (cxx_pretty_printer *pp, tr
       pop_deferring_access_checks ();
       /* Strip typedefs.  We can't just use TFF_CHASE_TYPEDEF because
         pp_simple_type_specifier doesn't know about it.  */
-      t = strip_typedefs (t);
+      t = strip_typedefs (t, tf_none);
       dump_type (pp, t, TFF_PLAIN_IDENTIFIER);
     }
 }
@@ -393,7 +393,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int fla
               || DECL_SELF_REFERENCE_P (decl)
               || (!flag_pretty_templates
                   && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)))
-       t = strip_typedefs (t);
+       t = strip_typedefs (t, tf_none);
       else if (alias_template_specialization_p (t))
        {
          dump_alias_template_specialization (pp, t, flags);
@@ -3115,7 +3115,7 @@ type_to_string (tree typ, int verbose)
       struct obstack *ob = pp_buffer (cxx_pp)->obstack;
       /* Remember the end of the initial dump.  */
       int len = obstack_object_size (ob);
-      tree aka = strip_typedefs (typ);
+      tree aka = strip_typedefs (typ, tf_none);
       pp_string (cxx_pp, " {aka");
       pp_cxx_whitespace (cxx_pp);
       /* And remember the start of the aka dump.  */
Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 244803)
+++ cp/pt.c     (working copy)
@@ -1140,12 +1140,13 @@ verify_unstripped_args (tree args)
          if (TREE_CODE (arg) == TEMPLATE_DECL)
            /* OK */;
          else if (TYPE_P (arg))
-           gcc_assert (strip_typedefs (arg, NULL) == arg);
-         else if (strip_typedefs (TREE_TYPE (arg), NULL) != TREE_TYPE (arg))
+           gcc_assert (strip_typedefs (arg, tf_none, NULL) == arg);
+         else if (strip_typedefs (TREE_TYPE (arg),
+                                  tf_none, NULL) != TREE_TYPE (arg))
            /* Allow typedefs on the type of a non-type argument, since a
               parameter can have them.  */;
          else
-           gcc_assert (strip_typedefs_expr (arg, NULL) == arg);
+           gcc_assert (strip_typedefs_expr (arg, tf_none, NULL) == arg);
        }
     }
   --processing_template_decl;
@@ -7312,7 +7313,7 @@ canonicalize_type_argument (tree arg, tsubst_flags
   if (!arg || arg == error_mark_node || arg == TYPE_CANONICAL (arg))
     return arg;
   bool removed_attributes = false;
-  tree canon = strip_typedefs (arg, &removed_attributes);
+  tree canon = strip_typedefs (arg, complain, &removed_attributes);
   if (removed_attributes
       && (complain & tf_warning))
     warning (OPT_Wignored_attributes,
@@ -7328,7 +7329,7 @@ canonicalize_expr_argument (tree arg, tsubst_flags
   if (!arg || arg == error_mark_node)
     return arg;
   bool removed_attributes = false;
-  tree canon = strip_typedefs_expr (arg, &removed_attributes);
+  tree canon = strip_typedefs_expr (arg, complain, &removed_attributes);
   if (removed_attributes
       && (complain & tf_warning))
     warning (OPT_Wignored_attributes,
@@ -20536,7 +20537,7 @@ unify (tree tparms, tree targs, tree parm, tree ar
 
       {
        bool removed_attr = false;
-       arg = strip_typedefs_expr (arg, &removed_attr);
+       arg = strip_typedefs_expr (arg, complain, &removed_attr);
       }
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
       return unify_success (explain_p);
Index: cp/semantics.c
===================================================================
--- cp/semantics.c      (revision 244803)
+++ cp/semantics.c      (working copy)
@@ -8991,7 +8991,7 @@ finish_decltype_type (tree expr, bool id_expressio
 
          /* For vector types, pick a non-opaque variant.  */
          if (VECTOR_TYPE_P (type))
-           type = strip_typedefs (type);
+           type = strip_typedefs (type, complain);
 
          if (clk != clk_none && !(clk & clk_class))
            type = cp_build_reference_type (type, (clk & clk_rvalueref));
Index: cp/tree.c
===================================================================
--- cp/tree.c   (revision 244803)
+++ cp/tree.c   (working copy)
@@ -1328,7 +1328,7 @@ apply_identity_attributes (tree result, tree attri
    stripped.  */
 
 tree
-strip_typedefs (tree t, bool *remove_attributes)
+strip_typedefs (tree t, tsubst_flags_t complain, bool *remove_attributes)
 {
   tree result = NULL, type = NULL, t0 = NULL;
 
@@ -1343,7 +1343,8 @@ tree
       for (; t; t = TREE_CHAIN (t))
        {
          gcc_assert (!TREE_PURPOSE (t));
-         tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes);
+         tree elt = strip_typedefs (TREE_VALUE (t), complain,
+                                    remove_attributes);
          if (elt != TREE_VALUE (t))
            changed = true;
          vec_safe_push (vec, elt);
@@ -1367,28 +1368,30 @@ tree
   switch (TREE_CODE (t))
     {
     case POINTER_TYPE:
-      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+      type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
       result = build_pointer_type (type);
       break;
     case REFERENCE_TYPE:
-      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+      type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
       result = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
       break;
     case OFFSET_TYPE:
-      t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes);
-      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+      t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), complain,
+                          remove_attributes);
+      type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
       result = build_offset_type (t0, type);
       break;
     case RECORD_TYPE:
       if (TYPE_PTRMEMFUNC_P (t))
        {
-         t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), remove_attributes);
+         t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), complain,
+                              remove_attributes);
          result = build_ptrmemfunc_type (t0);
        }
       break;
     case ARRAY_TYPE:
-      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
-      t0  = strip_typedefs (TYPE_DOMAIN (t), remove_attributes);
+      type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
+      t0  = strip_typedefs (TYPE_DOMAIN (t), complain, remove_attributes);
       result = build_cplus_array_type (type, t0);
       break;
     case FUNCTION_TYPE:
@@ -1407,7 +1410,7 @@ tree
            && (TYPE_ATTRIBUTES (t) || TYPE_USER_ALIGN (t)))
          is_variant = true;
 
-       type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+       type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
        changed = type != TREE_TYPE (t) || is_variant;
 
        for (arg_node = TYPE_ARG_TYPES (t);
@@ -1417,6 +1420,7 @@ tree
            if (arg_node == void_list_node)
              break;
            arg_type = strip_typedefs (TREE_VALUE (arg_node),
+                                      complain,
                                       remove_attributes);
            gcc_assert (arg_type);
            if (arg_type == TREE_VALUE (arg_node) && !changed)
@@ -1488,9 +1492,11 @@ tree
                tree arg = TREE_VEC_ELT (args, i);
                tree strip_arg;
                if (TYPE_P (arg))
-                 strip_arg = strip_typedefs (arg, remove_attributes);
+                 strip_arg = strip_typedefs (arg, complain,
+                                             remove_attributes);
                else
-                 strip_arg = strip_typedefs_expr (arg, remove_attributes);
+                 strip_arg = strip_typedefs_expr (arg, complain,
+                                                  remove_attributes);
                TREE_VEC_ELT (new_args, i) = strip_arg;
                if (strip_arg != arg)
                  changed = true;
@@ -1507,8 +1513,11 @@ tree
              ggc_free (new_args);
          }
        result = make_typename_type (strip_typedefs (TYPE_CONTEXT (t),
+                                                    complain,
                                                     remove_attributes),
-                                    fullname, typename_type, tf_none);
+                                    fullname, typename_type, complain);
+       if (result == error_mark_node)
+         return error_mark_node;
        /* Handle 'typedef typename A::N N;'  */
        if (typedef_variant_p (result))
          result = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (TYPE_NAME (result)));
@@ -1516,14 +1525,19 @@ tree
       break;
     case DECLTYPE_TYPE:
       result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t),
+                                   complain,
                                    remove_attributes);
       if (result == DECLTYPE_TYPE_EXPR (t))
        result = NULL_TREE;
       else
-       result = (finish_decltype_type
-                 (result,
-                  DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
-                  tf_none));
+       {
+         result = (finish_decltype_type
+                   (result,
+                    DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
+                    complain));
+         if (result == error_mark_node)
+           return error_mark_node;
+       }
       break;
     default:
       break;
@@ -1536,7 +1550,7 @@ tree
          /* Explicitly get the underlying type, as TYPE_MAIN_VARIANT doesn't
             strip typedefs with attributes.  */
          result = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (TYPE_NAME (t)));
-         result = strip_typedefs (result);
+         result = strip_typedefs (result, complain);
        }
       else
        result = TYPE_MAIN_VARIANT (t);
@@ -1579,7 +1593,7 @@ tree
    sizeof(TT) is replaced by sizeof(T).  */
 
 tree
-strip_typedefs_expr (tree t, bool *remove_attributes)
+strip_typedefs_expr (tree t, tsubst_flags_t complain, bool *remove_attributes)
 {
   unsigned i,n;
   tree r, type, *ops;
@@ -1594,7 +1608,7 @@ tree
   /* Some expressions have type operands, so let's handle types here rather
      than check TYPE_P in multiple places below.  */
   if (TYPE_P (t))
-    return strip_typedefs (t, remove_attributes);
+    return strip_typedefs (t, complain, remove_attributes);
 
   code = TREE_CODE (t);
   switch (code)
@@ -1608,8 +1622,10 @@ tree
 
     case TRAIT_EXPR:
       {
-       tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), remove_attributes);
-       tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), remove_attributes);
+       tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), complain,
+                                    remove_attributes);
+       tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), complain,
+                                    remove_attributes);
        if (type1 == TRAIT_EXPR_TYPE1 (t)
            && type2 == TRAIT_EXPR_TYPE2 (t))
          return t;
@@ -1626,7 +1642,8 @@ tree
        tree it;
        for (it = t; it; it = TREE_CHAIN (it))
          {
-           tree val = strip_typedefs_expr (TREE_VALUE (t), remove_attributes);
+           tree val = strip_typedefs_expr (TREE_VALUE (t), complain,
+                                           remove_attributes);
            vec_safe_push (vec, val);
            if (val != TREE_VALUE (t))
              changed = true;
@@ -1652,7 +1669,7 @@ tree
        vec_safe_reserve (vec, n);
        for (i = 0; i < n; ++i)
          {
-           tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i),
+           tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i), complain,
                                           remove_attributes);
            vec->quick_push (op);
            if (op != TREE_VEC_ELT (t, i))
@@ -1678,11 +1695,12 @@ tree
        vec<constructor_elt, va_gc> *vec
          = vec_safe_copy (CONSTRUCTOR_ELTS (t));
        n = CONSTRUCTOR_NELTS (t);
-       type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+       type = strip_typedefs (TREE_TYPE (t), complain, remove_attributes);
        for (i = 0; i < n; ++i)
          {
            constructor_elt *e = &(*vec)[i];
-           tree op = strip_typedefs_expr (e->value, remove_attributes);
+           tree op = strip_typedefs_expr (e->value, complain,
+                                          remove_attributes);
            if (op != e->value)
              {
                changed = true;
@@ -1689,7 +1707,8 @@ tree
                e->value = op;
              }
            gcc_checking_assert
-             (e->index == strip_typedefs_expr (e->index, remove_attributes));
+             (e->index == strip_typedefs_expr (e->index, complain,
+                                               remove_attributes));
          }
 
        if (!changed && type == TREE_TYPE (t))
@@ -1707,7 +1726,8 @@ tree
       }
 
     case LAMBDA_EXPR:
-      error ("lambda-expression in a constant expression");
+      if (complain & tf_error)
+       error ("lambda-expression in a constant expression");
       return error_mark_node;
 
     default:
@@ -1730,12 +1750,13 @@ tree
     case REINTERPRET_CAST_EXPR:
     case CAST_EXPR:
     case NEW_EXPR:
-      type = strip_typedefs (type, remove_attributes);
+      type = strip_typedefs (type, complain, remove_attributes);
       /* fallthrough */
 
     default:
       for (i = 0; i < n; ++i)
-       ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), remove_attributes);
+       ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), complain,
+                                     remove_attributes);
       break;
     }
 
Index: testsuite/g++.dg/cpp0x/pr72764.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr72764.C    (revision 0)
+++ testsuite/g++.dg/cpp0x/pr72764.C    (working copy)
@@ -0,0 +1,15 @@
+// PR c++/72764
+// { dg-do compile { target c++11 } }
+
+template < typename > struct A;
+template < typename > struct B {};
+
+template < typename T >
+using C = typename A < T >::template D < T >;
+
+template < typename T > struct A
+{ 
+  struct D : B < C < T > > {};  // { dg-error "not a class template" }
+};
+
+A < int > a;

Reply via email to