re PR c++/18368 (C++ error message regression)
authorMark Mitchell <mark@codesourcery.com>
Mon, 29 Nov 2004 20:10:18 +0000 (20:10 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 29 Nov 2004 20:10:18 +0000 (20:10 +0000)
PR c++/18368
* parser.c (cp_parser_check_for_definition_in_return_type): Take
the defined type as a parameter, and inform the user about the
possibility of a missing semicolon.
(cp_parser_explicit_instantiation): Adjust call to
cp_parser_check_for_definition_in_return_type.
(cp_parser_init_declarator): Likewise.
(cp_parser_member_declaration): Likewise.

PR c++/18674
* cp-tree.def (TYPENAME_TYPE): Remove discussion of implicit
typename from comments.
* cp-tree.h (TYPENAME_IS_ENUM_P): New macro.
(TYPENAME_IS_CLASS_P): Likewise.
(make_typename_type): Change prototype.
* decl.c (struct_typename_info): New type.
(typename_compare): Expect the second argument to be a
typename_info, not a tree.
(build_typename_type): Add tag_type parameter.  Do not create a
new type until necessary.
(make_typename_type): Add tag_type parameter.
* error.c (TYPENAME_TYPE): Print tags other than "typename" if
appropriate.
* friend.c (make_friend_class): Adjust call to make_typename_type.
* parser.c (cp_parser_make_typename_type): Likewise.
(cp_parser_primary_expression): Adjust call to
cp_parser_lookup_name.
(cp_parser_unqualified_id): Adjust calls to cp_parser_class_name.
(cp_parser_class_or_namespace_name): Likewise.
(cp_parser_postfix_expression): Adjust calls to
make_typename_type.
(cp_parser_mem_initializer_id): Adjust calls to
cp_parser_class_name.
(cp_parser_type_parameter): Adjust calls to cp_parser_lookup_name.
(cp_parser_template_name): Likewise.
(cp_parser_template_argument): Likewise.
(cp_parser_type_name): Adjust call to cp_parser_class_name.
(cp_parser_elaborated_type_specifier): Adjust calls to
make_typename_type and cp_parser_lookup_name.
(cp_parser_namespace_name): Likewise.
(cp_parser_class_name): Replace type_p parameter with tag_type.
Adjust calls to make_typename_type and cp_parser_lookup_name.
(cp_parser_class_head): Adjust calls to cp_parser_class_name.
(cp_parser_base_specifier): Likewise.
(cp_parser_lookup_name): Replace is_type parameter with tag_type.
Adjust calls to make_typename_type and lookup_qualified_name.
(cp_parser_lookup_name_simple): Adjust call to
cp_parser_lookup_name.
(cp_parser_constructor_declarator_p): Adjust call to
cp_parser_class_name.
* pt.c (convert_template_argument): Adjust all to
make_typename_type.
(tsubst_decl): Do not pre-substitute the type of the declaration.
(tsubst): Hand off declarations more quickly.  Adjust call to
make_typename_type.

PR c++/18512
* parser.c (cp_parser_postfix_dot_deref_expression): Robustify.

PR c++/18674
* g++.old-deja/g++.brendan/crash16.C: Adjust error messages.
* g++.old-deja/g++.law/ctors5.C: Likewise.
* g++.old-deja/g++.other/crash25.C: Likewise.

PR c++/18674
* g++.dg/template/error16.C: New test.

PR c++/18512
* g++.dg/template/crash29.C: New test.

From-SVN: r91483

14 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/friend.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/crash29.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/error16.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.brendan/crash16.C
gcc/testsuite/g++.old-deja/g++.law/ctors5.C
gcc/testsuite/g++.old-deja/g++.other/crash25.C

index 1a1dcbe..449be96 100644 (file)
@@ -1,3 +1,64 @@
+2004-11-27  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/18368
+       * parser.c (cp_parser_check_for_definition_in_return_type): Take
+       the defined type as a parameter, and inform the user about the
+       possibility of a missing semicolon.
+       (cp_parser_explicit_instantiation): Adjust call to
+       cp_parser_check_for_definition_in_return_type.
+       (cp_parser_init_declarator): Likewise.
+       (cp_parser_member_declaration): Likewise.
+
+       PR c++/18674
+       * cp-tree.def (TYPENAME_TYPE): Remove discussion of implicit
+       typename from comments.
+       * cp-tree.h (TYPENAME_IS_ENUM_P): New macro.
+       (TYPENAME_IS_CLASS_P): Likewise.
+       (make_typename_type): Change prototype.
+       * decl.c (struct_typename_info): New type.
+       (typename_compare): Expect the second argument to be a
+       typename_info, not a tree.
+       (build_typename_type): Add tag_type parameter.  Do not create a
+       new type until necessary.
+       (make_typename_type): Add tag_type parameter.
+       * error.c (TYPENAME_TYPE): Print tags other than "typename" if
+       appropriate.
+       * friend.c (make_friend_class): Adjust call to make_typename_type.
+       * parser.c (cp_parser_make_typename_type): Likewise.
+       (cp_parser_primary_expression): Adjust call to
+       cp_parser_lookup_name.
+       (cp_parser_unqualified_id): Adjust calls to cp_parser_class_name.
+       (cp_parser_class_or_namespace_name): Likewise.
+       (cp_parser_postfix_expression): Adjust calls to
+       make_typename_type.
+       (cp_parser_mem_initializer_id): Adjust calls to
+       cp_parser_class_name.
+       (cp_parser_type_parameter): Adjust calls to cp_parser_lookup_name.
+       (cp_parser_template_name): Likewise.
+       (cp_parser_template_argument): Likewise.
+       (cp_parser_type_name): Adjust call to cp_parser_class_name.
+       (cp_parser_elaborated_type_specifier): Adjust calls to
+       make_typename_type and cp_parser_lookup_name.
+       (cp_parser_namespace_name): Likewise.
+       (cp_parser_class_name): Replace type_p parameter with tag_type.
+       Adjust calls to make_typename_type and cp_parser_lookup_name.
+       (cp_parser_class_head): Adjust calls to cp_parser_class_name.
+       (cp_parser_base_specifier): Likewise.
+       (cp_parser_lookup_name): Replace is_type parameter with tag_type.
+       Adjust calls to make_typename_type and lookup_qualified_name.
+       (cp_parser_lookup_name_simple): Adjust call to
+       cp_parser_lookup_name.
+       (cp_parser_constructor_declarator_p): Adjust call to
+       cp_parser_class_name.
+       * pt.c (convert_template_argument): Adjust all to
+       make_typename_type.
+       (tsubst_decl): Do not pre-substitute the type of the declaration.
+       (tsubst): Hand off declarations more quickly.  Adjust call to
+       make_typename_type. 
+
+       PR c++/18512
+       * parser.c (cp_parser_postfix_dot_deref_expression): Robustify.
+
 2004-11-29  Daniel Jacobowitz  <dan@codesourcery.com>
 
        PR c/7544
index 2335e2f..a01ed76 100644 (file)
@@ -182,9 +182,7 @@ DEFTREECODE (BOUND_TEMPLATE_TEMPLATE_PARM, "bound_template_template_parm",
 /* A type designated by `typename T::t'.  TYPE_CONTEXT is `T',
    TYPE_NAME is an IDENTIFIER_NODE for `t'.  If the type was named via
    template-id, TYPENAME_TYPE_FULLNAME will hold the TEMPLATE_ID_EXPR.
-   If TREE_TYPE is present, this type was generated by the implicit
-   typename extension, and the TREE_TYPE is a _TYPE from a baseclass
-   of `T'.  */
+   TREE_TYPE is always NULL.  */
 DEFTREECODE (TYPENAME_TYPE, "typename_type", tcc_type, 0)
 
 /* For template template argument of the form `T::template C'.
index 1dfd52d..ecc09cd 100644 (file)
@@ -47,6 +47,7 @@ struct diagnostic_context;
       STATEMENT_LIST_NO_SCOPE (in STATEMENT_LIST).
       EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
       BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
+      TYPENAME_IS_ENUM_P (in TYPENAME_TYPE)
    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -54,6 +55,7 @@ struct diagnostic_context;
       (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out).
       ICS_ELLIPSIS_FLAG (in _CONV)
       DECL_INITIALIZED_P (in VAR_DECL)
+      TYPENAME_IS_CLASS_P (in TYPENAME_TYPE)
    2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -2254,6 +2256,15 @@ struct lang_decl GTY(())
    TEMPLATE_ID_EXPR if we had something like `typename X::Y<T>'.  */
 #define TYPENAME_TYPE_FULLNAME(NODE) (TYPENAME_TYPE_CHECK (NODE))->type.values
 
+/* True if a TYPENAME_TYPE was declared as an "enum".  */
+#define TYPENAME_IS_ENUM_P(NODE) \
+  (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE)))
+
+/* True if a TYPENAME_TYPE was declared as a "class", "struct", or
+   "union".  */
+#define TYPENAME_IS_CLASS_P(NODE) \
+  (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE)))
+
 /* Nonzero in INTEGER_CST means that this int is negative by dint of
    using a twos-complement negated operand.  */
 #define TREE_NEGATED_INT(NODE) TREE_LANG_FLAG_0 (INTEGER_CST_CHECK (NODE))
@@ -3718,7 +3729,7 @@ extern tree declare_local_label                 (tree);
 extern tree define_label                       (location_t, tree);
 extern void check_goto                         (tree);
 extern void define_case_label                  (void);
-extern tree make_typename_type                 (tree, tree, tsubst_flags_t);
+extern tree make_typename_type                 (tree, tree, enum tag_types, tsubst_flags_t);
 extern tree make_unbound_class_template                (tree, tree, tree, tsubst_flags_t);
 extern tree check_for_out_of_scope_variable     (tree);
 extern tree build_library_fn                   (tree, tree);
index 7779080..92f294f 100644 (file)
@@ -121,7 +121,6 @@ static void initialize_local_var (tree, tree);
 static void expand_static_init (tree, tree);
 static tree next_initializable_field (tree);
 static tree reshape_init (tree, tree *);
-static tree build_typename_type (tree, tree, tree);
 
 /* Erroneous argument lists can use this *IFF* they do not modify it.  */
 tree error_mark_list;
@@ -2538,83 +2537,101 @@ typename_hash (const void* k)
   return hash;
 }
 
+typedef struct typename_info {
+  tree scope;
+  tree name;
+  tree template_id;
+  bool enum_p;
+  bool class_p;
+} typename_info;
+
 /* Compare two TYPENAME_TYPEs.  K1 and K2 are really of type `tree'.  */
 
 static int
 typename_compare (const void * k1, const void * k2)
 {
   tree t1;
-  tree t2;
-  tree d1;
-  tree d2;
+  const typename_info *t2;
 
   t1 = (tree) k1;
-  t2 = (tree) k2;
-  d1 = TYPE_NAME (t1);
-  d2 = TYPE_NAME (t2);
+  t2 = (const typename_info *) k2;
 
-  return (DECL_NAME (d1) == DECL_NAME (d2)
-         && TYPE_CONTEXT (t1) == TYPE_CONTEXT (t2)
-         && ((TREE_TYPE (t1) != NULL_TREE)
-             == (TREE_TYPE (t2) != NULL_TREE))
-         && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
-         && TYPENAME_TYPE_FULLNAME (t1) == TYPENAME_TYPE_FULLNAME (t2));
+  return (DECL_NAME (TYPE_NAME (t1)) == t2->name
+         && TYPE_CONTEXT (t1) == t2->scope
+         && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
+         && TYPENAME_IS_ENUM_P (t1) == t2->enum_p
+         && TYPENAME_IS_CLASS_P (t1) == t2->class_p);
 }
 
 /* Build a TYPENAME_TYPE.  If the type is `typename T::t', CONTEXT is
-   the type of `T', NAME is the IDENTIFIER_NODE for `t'.  If BASE_TYPE
-   is non-NULL, this type is being created by the implicit typename
-   extension, and BASE_TYPE is a type named `t' in some base class of
-   `T' which depends on template parameters.
-
+   the type of `T', NAME is the IDENTIFIER_NODE for `t'.
    Returns the new TYPENAME_TYPE.  */
 
 static GTY ((param_is (union tree_node))) htab_t typename_htab;
 
 static tree
-build_typename_type (tree context, tree name, tree fullname)
+build_typename_type (tree context, tree name, tree fullname,
+                    enum tag_types tag_type)
 {
   tree t;
   tree d;
+  typename_info ti;
   void **e;
+  hashval_t hash;
 
   if (typename_htab == NULL)
-    {
-      typename_htab = htab_create_ggc (61, &typename_hash,
-                                      &typename_compare, NULL);
-    }
-
-  /* Build the TYPENAME_TYPE.  */
-  t = make_aggr_type (TYPENAME_TYPE);
-  TYPE_CONTEXT (t) = FROB_CONTEXT (context);
-  TYPENAME_TYPE_FULLNAME (t) = fullname;
-
-  /* Build the corresponding TYPE_DECL.  */
-  d = build_decl (TYPE_DECL, name, t);
-  TYPE_NAME (TREE_TYPE (d)) = d;
-  TYPE_STUB_DECL (TREE_TYPE (d)) = d;
-  DECL_CONTEXT (d) = FROB_CONTEXT (context);
-  DECL_ARTIFICIAL (d) = 1;
+    typename_htab = htab_create_ggc (61, &typename_hash,
+                                    &typename_compare, NULL);
+
+  ti.scope = FROB_CONTEXT (context); 
+  ti.name = name;
+  ti.template_id = fullname;
+  ti.enum_p = tag_type == enum_type;
+  ti.class_p = (tag_type == class_type
+               || tag_type == record_type
+               || tag_type == union_type);
+  hash =  (htab_hash_pointer (ti.scope)
+          ^ htab_hash_pointer (ti.name));
 
   /* See if we already have this type.  */
-  e = htab_find_slot (typename_htab, t, INSERT);
+  e = htab_find_slot_with_hash (typename_htab, &ti, hash, INSERT);
   if (*e)
     t = (tree) *e;
   else
-    *e = t;
+    {
+      /* Build the TYPENAME_TYPE.  */
+      t = make_aggr_type (TYPENAME_TYPE);
+      TYPE_CONTEXT (t) = ti.scope;
+      TYPENAME_TYPE_FULLNAME (t) = ti.template_id;
+      TYPENAME_IS_ENUM_P (t) = ti.enum_p;
+      TYPENAME_IS_CLASS_P (t) = ti.class_p;
+      
+      /* Build the corresponding TYPE_DECL.  */
+      d = build_decl (TYPE_DECL, name, t);
+      TYPE_NAME (TREE_TYPE (d)) = d;
+      TYPE_STUB_DECL (TREE_TYPE (d)) = d;
+      DECL_CONTEXT (d) = FROB_CONTEXT (context);
+      DECL_ARTIFICIAL (d) = 1;
 
+      /* Store it in the hash table.  */
+      *e = t;
+    }
+      
   return t;
 }
 
-/* Resolve `typename CONTEXT::NAME'.  Returns an appropriate type,
-   unless an error occurs, in which case error_mark_node is returned.
-   If we locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is
-   set, we return that, rather than the _TYPE it corresponds to, in
-   other cases we look through the type decl.  If TF_ERROR is set,
-   complain about errors, otherwise be quiet.  */
+/* Resolve `typename CONTEXT::NAME'.  TAG_TYPE indicates the tag
+   provided to name the type.  Returns an appropriate type, unless an
+   error occurs, in which case error_mark_node is returned.  If we
+   locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is set, we
+   return that, rather than the _TYPE it corresponds to, in other
+   cases we look through the type decl.  If TF_ERROR is set, complain
+   about errors, otherwise be quiet.  */
 
 tree
-make_typename_type (tree context, tree name, tsubst_flags_t complain)
+make_typename_type (tree context, tree name, enum tag_types tag_type,
+                   tsubst_flags_t complain)
 {
   tree fullname;
 
@@ -2728,7 +2745,7 @@ make_typename_type (tree context, tree name, tsubst_flags_t complain)
       return error_mark_node;
     }
 
-  return build_typename_type (context, name, fullname);
+  return build_typename_type (context, name, fullname, tag_type);
 }
 
 /* Resolve `CONTEXT::template NAME'.  Returns a TEMPLATE_DECL if the name
index 2f14db6..ffdade0 100644 (file)
@@ -348,7 +348,10 @@ dump_type (tree t, int flags)
     }
     case TYPENAME_TYPE:
       pp_cxx_cv_qualifier_seq (cxx_pp, t);
-      pp_cxx_identifier (cxx_pp, "typename");
+      pp_cxx_identifier (cxx_pp, 
+                        TYPENAME_IS_ENUM_P (t) ? "enum" 
+                        : TYPENAME_IS_CLASS_P (t) ? "class"
+                        : "typename");
       dump_typename (t, flags);
       break;
 
index 2d177a0..8203dbb 100644 (file)
@@ -300,7 +300,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
                                                 tf_error);
              else
                friend_type
-                 = make_typename_type (ctype, name, tf_error);
+                 = make_typename_type (ctype, name, class_type, tf_error);
            }
          else
            {
index b2164b7..ebcf852 100644 (file)
@@ -1514,7 +1514,7 @@ static bool cp_parser_ctor_initializer_opt_and_function_body
 /* Classes [gram.class] */
 
 static tree cp_parser_class_name
-  (cp_parser *, bool, bool, bool, bool, bool, bool);
+  (cp_parser *, bool, bool, enum tag_types, bool, bool, bool);
 static tree cp_parser_class_specifier
   (cp_parser *);
 static tree cp_parser_class_head
@@ -1623,7 +1623,7 @@ static void cp_parser_label_declaration
 /* Utility Routines */
 
 static tree cp_parser_lookup_name
-  (cp_parser *, tree, bool, bool, bool, bool, bool *);
+  (cp_parser *, tree, enum tag_types, bool, bool, bool, bool *);
 static tree cp_parser_lookup_name_simple
   (cp_parser *, tree);
 static tree cp_parser_maybe_treat_template_as_class
@@ -1713,7 +1713,7 @@ static bool cp_parser_simulate_error
 static void cp_parser_check_type_definition
   (cp_parser *);
 static void cp_parser_check_for_definition_in_return_type
-  (cp_declarator *, int);
+  (cp_declarator *, tree);
 static void cp_parser_check_for_invalid_template_id
   (cp_parser *, tree);
 static bool cp_parser_non_integral_constant_expression
@@ -1861,14 +1861,14 @@ cp_parser_check_type_definition (cp_parser* parser)
     error ("%s", parser->type_definition_forbidden_message);
 }
 
-/* This function is called when a declaration is parsed.  If
-   DECLARATOR is a function declarator and DECLARES_CLASS_OR_ENUM
-   indicates that a type was defined in the decl-specifiers for DECL,
-   then an error is issued.  */
+/* This function is called when the DECLARATOR is processed.  The TYPE
+   was a type definied in the decl-specifiers.  If it is invalid to
+   define a type in the decl-specifiers for DECLARATOR, an error is
+   issued.  */
 
 static void
 cp_parser_check_for_definition_in_return_type (cp_declarator *declarator,
-                                              int declares_class_or_enum)
+                                              tree type)
 {
   /* [dcl.fct] forbids type definitions in return types.
      Unfortunately, it's not easy to know whether or not we are
@@ -1879,9 +1879,12 @@ cp_parser_check_for_definition_in_return_type (cp_declarator *declarator,
             || declarator->kind == cdk_ptrmem))
     declarator = declarator->declarator;
   if (declarator
-      && declarator->kind == cdk_function
-      && declares_class_or_enum & 2)
-    error ("new types may not be defined in a return type");
+      && declarator->kind == cdk_function)
+    {
+      error ("new types may not be defined in a return type");
+      inform ("(perhaps a semicolon is missing after the definition of %qT)",
+             type);
+    }
 }
 
 /* A type-specifier (TYPE) has been parsed which cannot be followed by
@@ -2295,12 +2298,13 @@ cp_parser_make_typename_type (cp_parser *parser, tree scope, tree id)
   tree result;
   if (TREE_CODE (id) == IDENTIFIER_NODE)
     {
-      result = make_typename_type (scope, id, /*complain=*/0);
+      result = make_typename_type (scope, id, typename_type,
+                                  /*complain=*/0);
       if (result == error_mark_node)
        cp_parser_diagnose_invalid_type_name (parser, scope, id);
       return result;
     }
-  return make_typename_type (scope, id, tf_error);
+  return make_typename_type (scope, id, typename_type, tf_error);
 }
 
 
@@ -2831,7 +2835,7 @@ cp_parser_primary_expression (cp_parser *parser,
            bool ambiguous_p;
 
            decl = cp_parser_lookup_name (parser, id_expression,
-                                         /*is_type=*/false,
+                                         none_type,
                                          /*is_template=*/false,
                                          /*is_namespace=*/false,
                                          /*check_dependency=*/true,
@@ -3164,7 +3168,7 @@ cp_parser_unqualified_id (cp_parser* parser,
            type_decl = cp_parser_class_name (parser,
                                              /*typename_keyword_p=*/false,
                                              /*template_keyword_p=*/false,
-                                             /*type_p=*/false,
+                                             none_type,
                                              /*check_dependency=*/false,
                                              /*class_head_p=*/false,
                                              declarator_p);
@@ -3182,7 +3186,7 @@ cp_parser_unqualified_id (cp_parser* parser,
              = cp_parser_class_name (parser,
                                      /*typename_keyword_p=*/false,
                                      /*template_keyword_p=*/false,
-                                     /*type_p=*/false,
+                                     none_type,
                                      /*check_dependency=*/false,
                                      /*class_head_p=*/false,
                                      declarator_p);
@@ -3200,7 +3204,7 @@ cp_parser_unqualified_id (cp_parser* parser,
              = cp_parser_class_name (parser,
                                      /*typename_keyword_p=*/false,
                                      /*template_keyword_p=*/false,
-                                     /*type_p=*/false,
+                                     none_type,
                                      /*check_dependency=*/false,
                                      /*class_head_p=*/false,
                                      declarator_p);
@@ -3215,7 +3219,7 @@ cp_parser_unqualified_id (cp_parser* parser,
          = cp_parser_class_name (parser,
                                  /*typename_keyword_p=*/false,
                                  /*template_keyword_p=*/false,
-                                 /*type_p=*/false,
+                                 none_type,
                                  /*check_dependency=*/false,
                                  /*class_head_p=*/false,
                                  declarator_p);
@@ -3579,7 +3583,7 @@ cp_parser_class_or_namespace_name (cp_parser *parser,
   scope = cp_parser_class_name (parser,
                                typename_keyword_p,
                                template_keyword_p,
-                               type_p,
+                               type_p ? class_type : none_type,
                                check_dependency_p,
                                /*class_head_p=*/false,
                                is_declaration);
@@ -3815,6 +3819,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
           functional cast is being performed.  */
        else
          type = make_typename_type (parser->scope, id,
+                                    typename_type,
                                     /*complain=*/1);
 
        postfix_expression = cp_parser_functional_cast (parser, type);
@@ -4275,18 +4280,28 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
       if (parser->scope)
        *idk = CP_ID_KIND_QUALIFIED;
 
-      if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
+      /* If the name is a template-id that names a type, we will get a
+        TYPE_DECL here.  That is invalid code.  */
+      if (TREE_CODE (name) == TYPE_DECL)
        {
-         name = build_nt (SCOPE_REF, parser->scope, name);
-         parser->scope = NULL_TREE;
-         parser->qualifying_scope = NULL_TREE;
-         parser->object_scope = NULL_TREE;
+         error ("invalid use of %qD", name);
+         postfix_expression = error_mark_node;
+       }
+      else
+       {
+         if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
+           {
+             name = build_nt (SCOPE_REF, parser->scope, name);
+             parser->scope = NULL_TREE;
+             parser->qualifying_scope = NULL_TREE;
+             parser->object_scope = NULL_TREE;
+           }
+         if (scope && name && BASELINK_P (name))
+           adjust_result_of_qualified_name_lookup
+             (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
+         postfix_expression
+           = finish_class_member_access_expr (postfix_expression, name);
        }
-      if (scope && name && BASELINK_P (name))
-       adjust_result_of_qualified_name_lookup
-         (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
-      postfix_expression
-       = finish_class_member_access_expr (postfix_expression, name);
     }
 
   /* We no longer need to look up names in the scope of the object on
@@ -7659,7 +7674,7 @@ cp_parser_mem_initializer_id (cp_parser* parser)
     return cp_parser_class_name (parser,
                                 /*typename_keyword_p=*/true,
                                 /*template_keyword_p=*/template_p,
-                                /*type_p=*/false,
+                                none_type,
                                 /*check_dependency_p=*/true,
                                 /*class_head_p=*/false,
                                 /*is_declaration=*/true);
@@ -7669,7 +7684,7 @@ cp_parser_mem_initializer_id (cp_parser* parser)
   id = cp_parser_class_name (parser,
                             /*typename_keyword_p=*/true,
                             /*template_keyword_p=*/false,
-                            /*type_p=*/false,
+                            none_type,
                             /*check_dependency_p=*/true,
                             /*class_head_p=*/false,
                             /*is_declaration=*/true);
@@ -8223,11 +8238,11 @@ cp_parser_type_parameter (cp_parser* parser)
              /* Look up the name.  */
              default_argument
                = cp_parser_lookup_name (parser, default_argument,
-                                       /*is_type=*/false,
-                                       /*is_template=*/is_template,
-                                       /*is_namespace=*/false,
-                                       /*check_dependency=*/true,
-                                       /*ambiguous_p=*/NULL);
+                                        none_type,
+                                        /*is_template=*/is_template,
+                                        /*is_namespace=*/false,
+                                        /*check_dependency=*/true,
+                                        /*ambiguous_p=*/NULL);
            /* See if the default argument is valid.  */
            default_argument
              = check_template_template_default_arg (default_argument);
@@ -8578,7 +8593,7 @@ cp_parser_template_name (cp_parser* parser,
 
   /* Look up the name.  */
   decl = cp_parser_lookup_name (parser, identifier,
-                               /*is_type=*/false,
+                               none_type,
                                /*is_template=*/false,
                                /*is_namespace=*/false,
                                check_dependency_p,
@@ -8769,7 +8784,7 @@ cp_parser_template_argument (cp_parser* parser)
         at this point in that case.  */
       if (TREE_CODE (argument) != TYPE_DECL)
        argument = cp_parser_lookup_name (parser, argument,
-                                         /*is_type=*/false,
+                                         none_type,
                                          /*is_template=*/template_p,
                                          /*is_namespace=*/false,
                                          /*check_dependency=*/true,
@@ -8971,8 +8986,9 @@ cp_parser_explicit_instantiation (cp_parser* parser)
                                /*ctor_dtor_or_conv_p=*/NULL,
                                /*parenthesized_p=*/NULL,
                                /*member_p=*/false);
-      cp_parser_check_for_definition_in_return_type (declarator,
-                                                    declares_class_or_enum);
+      if (declares_class_or_enum & 2)
+       cp_parser_check_for_definition_in_return_type (declarator,
+                                                      decl_specifiers.type);
       if (declarator != cp_error_declarator)
        {
          decl = grokdeclarator (declarator, &decl_specifiers,
@@ -9460,7 +9476,7 @@ cp_parser_type_name (cp_parser* parser)
   type_decl = cp_parser_class_name (parser,
                                    /*typename_keyword_p=*/false,
                                    /*template_keyword_p=*/false,
-                                   /*type_p=*/false,
+                                   none_type,
                                    /*check_dependency_p=*/true,
                                    /*class_head_p=*/false,
                                    /*is_declaration=*/false);
@@ -9612,6 +9628,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
       else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
               && tag_type == typename_type)
        type = make_typename_type (parser->scope, decl,
+                                  typename_type,
                                   /*complain=*/1);
       else
        type = TREE_TYPE (decl);
@@ -9641,7 +9658,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
             types, so we set IS_TYPE to TRUE when calling
             cp_parser_lookup_name.  */
          decl = cp_parser_lookup_name (parser, identifier,
-                                       /*is_type=*/true,
+                                       tag_type,
                                        /*is_template=*/false,
                                        /*is_namespace=*/false,
                                        /*check_dependency=*/true,
@@ -9929,7 +9946,7 @@ cp_parser_namespace_name (cp_parser* parser)
      function if the token after the name is the scope resolution
      operator.)  */
   namespace_decl = cp_parser_lookup_name (parser, identifier,
-                                         /*is_type=*/false,
+                                         none_type,
                                          /*is_template=*/false,
                                          /*is_namespace=*/true,
                                          /*check_dependency=*/true,
@@ -10416,8 +10433,9 @@ cp_parser_init_declarator (cp_parser* parser,
   if (declarator == cp_error_declarator)
     return error_mark_node;
 
-  cp_parser_check_for_definition_in_return_type (declarator,
-                                                declares_class_or_enum);
+  if (declares_class_or_enum & 2)
+    cp_parser_check_for_definition_in_return_type (declarator,
+                                                  decl_specifiers->type);
 
   /* Figure out what scope the entity declared by the DECLARATOR is
      located in.  `grokdeclarator' sometimes changes the scope, so
@@ -12100,11 +12118,10 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
    to indicate that names looked up in dependent types should be
    assumed to be types.  TEMPLATE_KEYWORD_P is true iff the `template'
    keyword has been used to indicate that the name that appears next
-   is a template.  TYPE_P is true iff the next name should be treated
-   as class-name, even if it is declared to be some other kind of name
-   as well.  If CHECK_DEPENDENCY_P is FALSE, names are looked up in
-   dependent scopes.  If CLASS_HEAD_P is TRUE, this class is the class
-   being defined in a class-head.
+   is a template.  TAG_TYPE indicates the explicit tag given before
+   the type name, if any.  If CHECK_DEPENDENCY_P is FALSE, names are
+   looked up in dependent scopes.  If CLASS_HEAD_P is TRUE, this class
+   is the class being defined in a class-head.
 
    Returns the TYPE_DECL representing the class.  */
 
@@ -12112,7 +12129,7 @@ static tree
 cp_parser_class_name (cp_parser *parser,
                      bool typename_keyword_p,
                      bool template_keyword_p,
-                     bool type_p,
+                     enum tag_types tag_type,
                      bool check_dependency_p,
                      bool class_head_p,
                      bool is_declaration)
@@ -12168,10 +12185,10 @@ cp_parser_class_name (cp_parser *parser,
             resolution operator, object, function, and enumerator
             names are ignored.  */
          if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
-           type_p = true;
+           tag_type = typename_type;
          /* Look up the name.  */
          decl = cp_parser_lookup_name (parser, identifier,
-                                       type_p,
+                                       tag_type,
                                        /*is_template=*/false,
                                        /*is_namespace=*/false,
                                        check_dependency_p,
@@ -12193,7 +12210,7 @@ cp_parser_class_name (cp_parser *parser,
   /* If this is a typename, create a TYPENAME_TYPE.  */
   if (typename_p && decl != error_mark_node)
     {
-      decl = make_typename_type (scope, decl, /*complain=*/1);
+      decl = make_typename_type (scope, decl, typename_type, /*complain=*/1);
       if (decl != error_mark_node)
        decl = TYPE_NAME (decl);
     }
@@ -12212,7 +12229,7 @@ cp_parser_class_name (cp_parser *parser,
        standard does not seem to be definitive, but there is no other
        valid interpretation of the following `::'.  Therefore, those
        names are considered class-names.  */
-    decl = TYPE_NAME (make_typename_type (scope, decl, tf_error));
+    decl = TYPE_NAME (make_typename_type (scope, decl, tag_type, tf_error));
   else if (decl == error_mark_node
           || TREE_CODE (decl) != TYPE_DECL
           || !IS_AGGR_TYPE (TREE_TYPE (decl)))
@@ -12500,7 +12517,7 @@ cp_parser_class_head (cp_parser* parser,
       type = cp_parser_class_name (parser,
                                   /*typename_keyword_p=*/false,
                                   /*template_keyword_p=*/false,
-                                  /*type_p=*/true,
+                                  class_type,
                                   /*check_dependency_p=*/false,
                                   /*class_head_p=*/true,
                                   /*is_declaration=*/false);
@@ -13058,8 +13075,9 @@ cp_parser_member_declaration (cp_parser* parser)
                  return;
                }
 
-             cp_parser_check_for_definition_in_return_type
-               (declarator, declares_class_or_enum);
+             if (declares_class_or_enum & 2)
+               cp_parser_check_for_definition_in_return_type
+                 (declarator, decl_specifiers.type);
 
              /* Look for an asm-specification.  */
              asm_specification = cp_parser_asm_specification_opt (parser);
@@ -13414,7 +13432,7 @@ cp_parser_base_specifier (cp_parser* parser)
   cp_parser_nested_name_specifier_opt (parser,
                                       /*typename_keyword_p=*/true,
                                       /*check_dependency_p=*/true,
-                                      /*type_p=*/true,
+                                      typename_type,
                                       /*is_declaration=*/true);
   /* If the base class is given by a qualified name, assume that names
      we see are type names or templates, as appropriate.  */
@@ -13425,7 +13443,7 @@ cp_parser_base_specifier (cp_parser* parser)
   type = cp_parser_class_name (parser,
                               class_scope_p,
                               template_p,
-                              /*type_p=*/true,
+                              typename_type,
                               /*check_dependency_p=*/true,
                               /*class_head_p=*/false,
                               /*is_declaration=*/true);
@@ -14049,8 +14067,9 @@ cp_parser_label_declaration (cp_parser* parser)
    If there was no entity with the indicated NAME, the ERROR_MARK_NODE
    is returned.
 
-   If IS_TYPE is TRUE, bindings that do not refer to types are
-   ignored.
+   If TAG_TYPE is not NONE_TYPE, it inidcates an explicit type keyword
+   (e.g., "struct") that was used.  In that case bindings that do not
+   refer to types are ignored.
 
    If IS_TEMPLATE is TRUE, bindings that do not refer to templates are
    ignored.
@@ -14066,7 +14085,8 @@ cp_parser_label_declaration (cp_parser* parser)
 
 static tree
 cp_parser_lookup_name (cp_parser *parser, tree name,
-                      bool is_type, bool is_template, bool is_namespace,
+                      enum tag_types tag_type,
+                      bool is_template, bool is_namespace,
                       bool check_dependency,
                       bool *ambiguous_p)
 {
@@ -14144,13 +14164,21 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
       if ((check_dependency || !CLASS_TYPE_P (parser->scope))
           && dependent_p)
        {
-         if (is_type)
-           /* The resolution to Core Issue 180 says that `struct A::B'
-              should be considered a type-name, even if `A' is
-              dependent.  */
-           decl = TYPE_NAME (make_typename_type (parser->scope,
-                                                 name,
-                                                 /*complain=*/1));
+         if (tag_type)
+           {
+             tree type;
+
+             /* The resolution to Core Issue 180 says that `struct
+                A::B' should be considered a type-name, even if `A'
+                is dependent.  */
+             type = make_typename_type (parser->scope, name, tag_type,
+                                        /*complain=*/1);
+             if (tag_type == enum_type)
+               TYPENAME_IS_ENUM_P (type) = 1;
+             else if (tag_type != typename_type)
+               TYPENAME_IS_CLASS_P (type) = 1;
+             decl = TYPE_NAME (type);
+           }
          else if (is_template)
            decl = make_unbound_class_template (parser->scope,
                                                name, NULL_TREE,
@@ -14173,7 +14201,8 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
             may be instantiated during name lookup.  In that case,
             errors may be issued.  Even if we rollback the current
             tentative parse, those errors are valid.  */
-         decl = lookup_qualified_name (parser->scope, name, is_type,
+         decl = lookup_qualified_name (parser->scope, name, 
+                                       tag_type != none_type, 
                                        /*complain=*/true);
          if (pop_p)
            pop_scope (parser->scope);
@@ -14193,9 +14222,11 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
           parse, those errors are valid.  */
        object_decl = lookup_member (object_type,
                                     name,
-                                    /*protect=*/0, is_type);
+                                    /*protect=*/0, 
+                                    tag_type != none_type);
       /* Look it up in the enclosing context, too.  */
-      decl = lookup_name_real (name, is_type, /*nonclass=*/0,
+      decl = lookup_name_real (name, tag_type != none_type, 
+                              /*nonclass=*/0,
                               /*block_p=*/true, is_namespace,
                               /*flags=*/0);
       parser->object_scope = object_type;
@@ -14205,7 +14236,8 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
     }
   else
     {
-      decl = lookup_name_real (name, is_type, /*nonclass=*/0,
+      decl = lookup_name_real (name, tag_type != none_type, 
+                              /*nonclass=*/0,
                               /*block_p=*/true, is_namespace,
                               /*flags=*/0);
       parser->qualifying_scope = NULL_TREE;
@@ -14261,7 +14293,7 @@ static tree
 cp_parser_lookup_name_simple (cp_parser* parser, tree name)
 {
   return cp_parser_lookup_name (parser, name,
-                               /*is_type=*/false,
+                               none_type,
                                /*is_template=*/false,
                                /*is_namespace=*/false,
                                /*check_dependency=*/true,
@@ -14519,7 +14551,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
       type_decl = cp_parser_class_name (parser,
                                        /*typename_keyword_p=*/false,
                                        /*template_keyword_p=*/false,
-                                       /*type_p=*/false,
+                                       none_type,
                                        /*check_dependency_p=*/false,
                                        /*class_head_p=*/false,
                                        /*is_declaration=*/false);
index fca3f3d..34e86c8 100644 (file)
@@ -140,7 +140,6 @@ static tree most_specialized (tree, tree, tree);
 static tree most_specialized_class (tree, tree);
 static int template_class_depth_real (tree, int);
 static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
-static tree tsubst_decl (tree, tree, tree, tsubst_flags_t);
 static tree tsubst_arg_types (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
 static void check_specialization_scope (void);
@@ -3833,6 +3832,7 @@ convert_template_argument (tree parm,
       
       arg = make_typename_type (TREE_OPERAND (arg, 0),
                                TREE_OPERAND (arg, 1),
+                               typename_type,
                                complain & tf_error);
       is_type = 1;
     }
@@ -6140,13 +6140,12 @@ tsubst_default_arguments (tree fn)
                                                    TREE_PURPOSE (arg));
 }
 
-/* Substitute the ARGS into the T, which is a _DECL.  TYPE is the
-   (already computed) substitution of ARGS into TREE_TYPE (T), if
-   appropriate.  Return the result of the substitution.  Issue error
-   and warning messages under control of COMPLAIN.  */
+/* Substitute the ARGS into the T, which is a _DECL.  Return the
+   result of the substitution.  Issue error and warning messages under
+   control of COMPLAIN.  */
 
 static tree
-tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
+tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 {
   location_t saved_loc;
   tree r = NULL_TREE;
@@ -6267,6 +6266,7 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
        tree argvec = NULL_TREE;
        tree *friends;
        tree gen_tmpl;
+       tree type;
        int member;
        int args_depth;
        int parms_depth;
@@ -6376,7 +6376,7 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
            member = 0;
            ctx = DECL_CONTEXT (t);
          }
-       type = tsubst (type, args, complain, in_decl);
+       type = tsubst (TREE_TYPE (t), args, complain, in_decl);
        if (type == error_mark_node)
          return error_mark_node;
 
@@ -6485,10 +6485,13 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
 
     case PARM_DECL:
       {
+       tree type;
+
        r = copy_node (t);
        if (DECL_TEMPLATE_PARM_P (t))
          SET_DECL_TEMPLATE_PARM_P (r);
 
+       type = tsubst (TREE_TYPE (t), args, complain, in_decl);
        TREE_TYPE (r) = type;
        c_apply_type_quals_to_decl (cp_type_quals (type), r);
 
@@ -6513,7 +6516,12 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
 
     case FIELD_DECL:
       {
+       tree type;
+
        r = copy_decl (t);
+       type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+       if (type == error_mark_node)
+         return error_mark_node;
        TREE_TYPE (r) = type;
        c_apply_type_quals_to_decl (cp_type_quals (type), r);
 
@@ -6541,19 +6549,6 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
       break;
 
     case TYPE_DECL:
-      if (TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
-         || t == TYPE_MAIN_DECL (TREE_TYPE (t)))
-       {
-         /* If this is the canonical decl, we don't have to mess with
-             instantiations, and often we can't (for typename, template
-            type parms and such).  Note that TYPE_NAME is not correct for
-            the above test if we've copied the type for a typedef.  */
-         r = TYPE_NAME (type);
-         break;
-       }
-
-      /* Fall through.  */
-
     case VAR_DECL:
       {
        tree argvec = NULL_TREE;
@@ -6561,8 +6556,25 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
        tree spec;
        tree tmpl = NULL_TREE;
        tree ctx;
+       tree type = NULL_TREE;
        int local_p;
 
+       if (TREE_CODE (t) == TYPE_DECL)
+         {
+           type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+           if (TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
+               || t == TYPE_MAIN_DECL (TREE_TYPE (t)))
+             {
+               /* If this is the canonical decl, we don't have to
+                  mess with instantiations, and often we can't (for
+                  typename, template type parms and such).  Note that
+                  TYPE_NAME is not correct for the above test if
+                  we've copied the type for a typedef.  */
+               r = TYPE_NAME (type);
+               break;
+             }
+         }
+       
        /* Assume this is a non-local variable.  */
        local_p = 0;
 
@@ -6600,6 +6612,9 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain)
        r = copy_decl (t);
        if (TREE_CODE (r) == VAR_DECL)
          {
+           type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+           if (type == error_mark_node)
+             return error_mark_node;
            type = complete_type (type);
            DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r)
              = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t);
@@ -6885,6 +6900,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       || TREE_CODE (t) == NAMESPACE_DECL)
     return t;
 
+  if (DECL_P (t))
+    return tsubst_decl (t, args, complain);
+
   if (TREE_CODE (t) == IDENTIFIER_NODE)
     type = IDENTIFIER_TYPE_VALUE (t);
   else
@@ -6892,9 +6910,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
   gcc_assert (type != unknown_type_node);
 
-  if (type && TREE_CODE (t) != FUNCTION_DECL
+  if (type
       && TREE_CODE (t) != TYPENAME_TYPE
-      && TREE_CODE (t) != TEMPLATE_DECL
       && TREE_CODE (t) != IDENTIFIER_NODE
       && TREE_CODE (t) != FUNCTION_TYPE
       && TREE_CODE (t) != METHOD_TYPE)
@@ -6902,9 +6919,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   if (type == error_mark_node)
     return error_mark_node;
 
-  if (DECL_P (t))
-    return tsubst_decl (t, args, type, complain);
-
   switch (TREE_CODE (t))
     {
     case RECORD_TYPE:
@@ -7364,7 +7378,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
              }
          }
 
-       f = make_typename_type (ctx, f,
+       f = make_typename_type (ctx, f, typename_type,
                                (complain & tf_error) | tf_keep_type_decl);
        if (f == error_mark_node)
          return f;
@@ -7374,6 +7388,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
            f = TREE_TYPE (f);
          }
        
+       if (TREE_CODE (f) != TYPENAME_TYPE)
+         {
+           if (TYPENAME_IS_ENUM_P (t) && TREE_CODE (f) != ENUMERAL_TYPE)
+             error ("%qT resolves to %qT, which is not an enumeration type", 
+                    t, f);
+           else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f))
+             error ("%qT resolves to %qT, which is is not a class type", 
+                    t, f);
+         }
+
        return cp_build_qualified_type_real
          (f, cp_type_quals (f) | cp_type_quals (t), complain);
       }
index 0f3bc3b..7a806bb 100644 (file)
@@ -1,3 +1,16 @@
+2004-11-29  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/18674
+       * g++.old-deja/g++.brendan/crash16.C: Adjust error messages.
+       * g++.old-deja/g++.law/ctors5.C: Likewise.
+       * g++.old-deja/g++.other/crash25.C: Likewise.
+
+       PR c++/18674
+       * g++.dg/template/error16.C: New test.
+       
+       PR c++/18512
+       * g++.dg/template/crash29.C: New test.
+
 2004-11-29  Diego Novillo  <dnovillo@redhat.com>
 
        PR tree-optimization/18712
diff --git a/gcc/testsuite/g++.dg/template/crash29.C b/gcc/testsuite/g++.dg/template/crash29.C
new file mode 100644 (file)
index 0000000..55953ed
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/18512
+
+template <int> struct A {};
+
+struct B : A<0>
+{
+  void foo() { this->A<0>; } // { dg-error "" }
+};
diff --git a/gcc/testsuite/g++.dg/template/error16.C b/gcc/testsuite/g++.dg/template/error16.C
new file mode 100644 (file)
index 0000000..0da024b
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/18674
+
+template <typename I>
+static void g() {
+  enum I::t a; // { dg-error "" }
+  (void) a;
+}
+
+struct B {
+  typedef int t;
+};
+
+void h()
+{
+  g<B>();
+}
index 8b91e6b..8fec8d1 100644 (file)
@@ -6,7 +6,7 @@ public:
       Graph(void) {}; // { dg-error "previously defined here" }
 }
 
-Graph::Graph(void)    // { dg-error "return type|redefinition" }
+Graph::Graph(void)    // { dg-error "return type|redefinition|semicolon" }
 {    N = 10;
 }
 
index d08805a..334b597 100644 (file)
@@ -20,7 +20,7 @@ class Y
   public:
     Y();
 }
-X::X( int xi ) // { dg-error "return type|X::X" }
+X::X( int xi ) // { dg-error "return type|X::X|semicolon" }
 {
     x = xi;
 }
index b18d99b..b8417e8 100644 (file)
@@ -7,7 +7,7 @@ public:
   virtual ~X();
 }
 
-X::x() // { dg-error "return type|member function" }
+X::x() // { dg-error "return type|member function|semicolon" }
 {
 }