]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/22137 (Internal error: Segmentation fault (program cc1plus))
authorMark Mitchell <mark@codesourcery.com>
Sun, 16 Oct 2005 19:38:57 +0000 (19:38 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sun, 16 Oct 2005 19:38:57 +0000 (19:38 +0000)
PR c++/22137
* cp-tree.h (QUALIFIED_NAME_IS_TEMPLATE): New macro.
(check_template_keyword): New function.
(finish_id_expression): Change prototoype.
(finish_qualified_id_expr): Change prototype.
(build_qualified_name): New function.
(finish_class_member_access_expr): Change prototype.
* init.c (build_offset_ref): Use build_qualified_name.
* mangle.c (write_expression): Likewise.
* parser.c (cp_parser_primary_expression): Remove qualifying_class
parameter.  Add address_p and template_arg_p.  Use
build_qualified_name.
(cp_parser_id_expression): Default *template_p to
template_keyword_p.  Check for invalid uses of the template
keyword.
(cp_parser_postfix_expression): Eliminate special handling for
qualified names.  Adjust call to cp_parser_primary_expression.
(cp_parser_postfix_dot_deref_expression): Adjust call to
cp_parser_id_expression and finish_class_member_access_expr.
(cp_parser_template_argument_list): Add comment.
(cp_parser_template_argument): Adjust use of
cp_parser_primary_expression.  Remove call to
finish_qualified_id_expr.
(cp_parser_lookup_name): Use build_qualified_name.
* pt.c (tsubst): Use build_qualified_name.
(tsubst_qualified_id): Likewise.  Adjust call to
finish_qualified_id_expr.
(tsubst_copy): Use build_qualified_name.
(tsubst_copy_and_build): Adjusts call to finish_id_expression and
finish_class_member_access_expr.
* semantics.c (finish_non_static_data_member): Use
build_qualified_name.
(finish_qualified_id_expr): Add template_p and template_arg_p
parameters.
(finish_id_expression): Remove qualifiying_class parameter.  Add
template_p, done, address_p, and template_arg_p.  Use
build_qualified_name.  Adjust calls to
finish_class_member_acess_expr.
* tree.c (build_qualified_name): New function.
* typeck.c (check_template_keyword): New function.
(finish_class_member_access_expr): Add template_p argument.  Check
for invalid uses of the template keyword.

PR c++/22137
* g++.dg/parse/template18.C: New test.
* g++.dg/template/nontype15.C: Likewise.

From-SVN: r105463

12 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/init.c
gcc/cp/mangle.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/template18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/nontype15.C [new file with mode: 0644]

index 51089eb9f90116a0dd7f1882f1f23fe442d93f68..9d3930fe23eb8f896374254b71a41094136b07a8 100644 (file)
@@ -1,3 +1,48 @@
+2005-10-16  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/22137
+       * cp-tree.h (QUALIFIED_NAME_IS_TEMPLATE): New macro.
+       (check_template_keyword): New function.
+       (finish_id_expression): Change prototoype.
+       (finish_qualified_id_expr): Change prototype.
+       (build_qualified_name): New function.
+       (finish_class_member_access_expr): Change prototype.
+       * init.c (build_offset_ref): Use build_qualified_name.
+       * mangle.c (write_expression): Likewise.
+       * parser.c (cp_parser_primary_expression): Remove qualifying_class
+       parameter.  Add address_p and template_arg_p.  Use
+       build_qualified_name.
+       (cp_parser_id_expression): Default *template_p to
+       template_keyword_p.  Check for invalid uses of the template
+       keyword.  
+       (cp_parser_postfix_expression): Eliminate special handling for
+       qualified names.  Adjust call to cp_parser_primary_expression.
+       (cp_parser_postfix_dot_deref_expression): Adjust call to
+       cp_parser_id_expression and finish_class_member_access_expr.
+       (cp_parser_template_argument_list): Add comment.
+       (cp_parser_template_argument): Adjust use of
+       cp_parser_primary_expression.  Remove call to
+       finish_qualified_id_expr.
+       (cp_parser_lookup_name): Use build_qualified_name. 
+       * pt.c (tsubst): Use build_qualified_name.
+       (tsubst_qualified_id): Likewise.  Adjust call to
+       finish_qualified_id_expr.
+       (tsubst_copy): Use build_qualified_name.
+       (tsubst_copy_and_build): Adjusts call to finish_id_expression and
+       finish_class_member_access_expr. 
+       * semantics.c (finish_non_static_data_member): Use
+       build_qualified_name.
+       (finish_qualified_id_expr): Add template_p and template_arg_p
+       parameters. 
+       (finish_id_expression): Remove qualifiying_class parameter.  Add
+       template_p, done, address_p, and template_arg_p.  Use
+       build_qualified_name.  Adjust calls to
+       finish_class_member_acess_expr.  
+       * tree.c (build_qualified_name): New function.
+       * typeck.c (check_template_keyword): New function.
+       (finish_class_member_access_expr): Add template_p argument.  Check
+       for invalid uses of the template keyword.
+       
 2005-10-15  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/21347
index 42eed5f6fd491e8ee47b2432c5023889925cf4cc..9a2becc3c94172ad678ced013220db6f9208120a 100644 (file)
@@ -51,6 +51,7 @@ struct diagnostic_context;
       BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
       TYPENAME_IS_ENUM_P (in TYPENAME_TYPE)
       REFERENCE_REF_P (in INDIRECT_EXPR)
+      QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -2933,6 +2934,11 @@ extern void decl_shadowed_for_var_insert (tree, tree);
 #define THUNK_TARGET(NODE)                             \
   (DECL_LANG_SPECIFIC (NODE)->u.f.befriending_classes)
 
+/* True for a SCOPE_REF iff the "template" keyword was used to
+   indicate that the qualified name denotes a template.  */
+#define QUALIFIED_NAME_IS_TEMPLATE(NODE) \
+  (TREE_LANG_FLAG_0 (SCOPE_REF_CHECK (NODE)))
+
 /* These macros provide convenient access to the various _STMT nodes
    created when parsing template declarations.  */
 #define TRY_STMTS(NODE)                TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0)
@@ -4200,9 +4206,11 @@ extern tree finish_template_type         (tree, tree, int);
 extern tree finish_base_specifier              (tree, tree, bool);
 extern void finish_member_declaration          (tree);
 extern void qualified_name_lookup_error                (tree, tree, tree);
+extern void check_template_keyword              (tree);
 extern tree finish_id_expression               (tree, tree, tree,
-                                                cp_id_kind *, tree *,
+                                                cp_id_kind *,
                                                 bool, bool, bool *,
+                                                bool, bool, bool, bool,
                                                 const char **);
 extern tree finish_typeof                      (tree);
 extern void finish_decl_cleanup                        (tree, tree);
@@ -4212,7 +4220,8 @@ extern void finish_mem_initializers               (tree);
 extern tree check_template_template_default_arg (tree);
 extern void expand_or_defer_fn                 (tree);
 extern void check_accessibility_of_qualified_id (tree, tree, tree);
-extern tree finish_qualified_id_expr           (tree, tree, bool, bool);
+extern tree finish_qualified_id_expr           (tree, tree, bool, bool,
+                                                bool, bool);
 extern void simplify_aggr_init_expr            (tree *);
 extern void finalize_nrv                       (tree *, tree, tree);
 extern void note_decl_for_pch                  (tree);
@@ -4242,6 +4251,7 @@ extern tree get_target_expr                       (tree);
 extern tree build_cplus_array_type             (tree, tree);
 extern tree hash_tree_cons                     (tree, tree, tree);
 extern tree hash_tree_chain                    (tree, tree);
+extern tree build_qualified_name                (tree, tree, tree, bool);
 extern int is_overloaded_fn                    (tree);
 extern tree get_first_fn                       (tree);
 extern tree ovl_cons                           (tree, tree);
@@ -4305,7 +4315,7 @@ extern tree inline_conversion                     (tree);
 extern tree decay_conversion                   (tree);
 extern tree default_conversion                 (tree);
 extern tree build_class_member_access_expr      (tree, tree, tree, bool);
-extern tree finish_class_member_access_expr     (tree, tree);
+extern tree finish_class_member_access_expr     (tree, tree, bool);
 extern tree build_x_indirect_ref               (tree, const char *);
 extern tree build_indirect_ref                 (tree, const char *);
 extern tree build_array_ref                    (tree, tree);
index 20c3b356352f8c1cc689fcd15f3ebe51ac4988a5..809b74fa98ad72db37a190a18786b37b9d24678e 100644 (file)
@@ -1344,7 +1344,8 @@ build_offset_ref (tree type, tree name, bool address_p)
     return name;
 
   if (dependent_type_p (type) || type_dependent_expression_p (name))
-    return build_min_nt (SCOPE_REF, type, name);
+    return build_qualified_name (NULL_TREE, type, name, 
+                                /*template_p=*/false);
 
   if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
     {
index 9dca2a56c55c3cf527eba53deca362e8f390ecdd..b07012252bbafc3a23fd48167cdc08ba14956fea 100644 (file)
@@ -2008,9 +2008,10 @@ write_expression (tree expr)
   if (code == PTRMEM_CST)
     {
       expr = build_nt (ADDR_EXPR,
-                      build_nt (SCOPE_REF,
-                                PTRMEM_CST_CLASS (expr),
-                                PTRMEM_CST_MEMBER (expr)));
+                      build_qualified_name (/*type=*/NULL_TREE,
+                                            PTRMEM_CST_CLASS (expr),
+                                            PTRMEM_CST_MEMBER (expr),
+                                            /*template_p=*/false));
       code = TREE_CODE (expr);
     }
 
@@ -2186,7 +2187,7 @@ write_expression (tree expr)
          for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
            {
              tree operand = TREE_OPERAND (expr, i);
-             /* As a GNU expression, the middle operand of a
+             /* As a GNU extension, the middle operand of a
                 conditional may be omitted.  Since expression
                 manglings are supposed to represent the input token
                 stream, there's no good way to mangle such an
index 469cc73699f1045a03dd955418774d58a98f84c3..7f279437196f657c56f39d0ab34ab5ec8c085cb4 100644 (file)
@@ -1381,7 +1381,7 @@ static bool cp_parser_translation_unit
 /* Expressions [gram.expr]  */
 
 static tree cp_parser_primary_expression
-  (cp_parser *, bool, cp_id_kind *, tree *);
+  (cp_parser *, bool, bool, bool, cp_id_kind *);
 static tree cp_parser_id_expression
   (cp_parser *, bool, bool, bool *, bool);
 static tree cp_parser_unqualified_id
@@ -2716,29 +2716,25 @@ cp_parser_translation_unit (cp_parser* parser)
    literal:
      __null
 
-   CAST_P is true if this primary expression is the target of a cast.
+   ADDRESS_P is true iff this expression was immediately preceded by
+   "&" and therefore might denote a pointer-to-member.  CAST_P is true
+   iff this expression is the target of a cast.  TEMPLATE_ARG_P is
+   true iff this expression is a tempalte argument.
 
-   Returns a representation of the expression.
-
-   *IDK indicates what kind of id-expression (if any) was present.
-
-   *QUALIFYING_CLASS is set to a non-NULL value if the id-expression can be
-   used as the operand of a pointer-to-member.  In that case,
-   *QUALIFYING_CLASS gives the class that is used as the qualifying
-   class in the pointer-to-member.  */
+   Returns a representation of the expression.  Upon return, *IDK
+   indicates what kind of id-expression (if any) was present.  */
 
 static tree
 cp_parser_primary_expression (cp_parser *parser,
+                             bool address_p,
                              bool cast_p,
-                             cp_id_kind *idk,
-                             tree *qualifying_class)
+                             bool template_arg_p,
+                             cp_id_kind *idk)
 {
   cp_token *token;
 
   /* Assume the primary expression is not an id-expression.  */
   *idk = CP_ID_KIND_NONE;
-  /* And that it cannot be used as pointer-to-member.  */
-  *qualifying_class = NULL_TREE;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -2964,6 +2960,8 @@ cp_parser_primary_expression (cp_parser *parser,
        tree id_expression;
        tree decl;
        const char *error_msg;
+       bool template_p;
+       bool done;
 
       id_expression:
        /* Parse the id-expression.  */
@@ -2971,15 +2969,22 @@ cp_parser_primary_expression (cp_parser *parser,
          = cp_parser_id_expression (parser,
                                     /*template_keyword_p=*/false,
                                     /*check_dependency_p=*/true,
-                                    /*template_p=*/NULL,
+                                    &template_p,
                                     /*declarator_p=*/false);
        if (id_expression == error_mark_node)
          return error_mark_node;
+       token = cp_lexer_peek_token (parser->lexer);
+       done = (token->type != CPP_OPEN_SQUARE
+               && token->type != CPP_OPEN_PAREN
+               && token->type != CPP_DOT
+               && token->type != CPP_DEREF
+               && token->type != CPP_PLUS_PLUS
+               && token->type != CPP_MINUS_MINUS);
        /* If we have a template-id, then no further lookup is
           required.  If the template-id was for a template-class, we
           will sometimes have a TYPE_DECL at this point.  */
-       else if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
-           || TREE_CODE (id_expression) == TYPE_DECL)
+       if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
+                || TREE_CODE (id_expression) == TYPE_DECL)
          decl = id_expression;
        /* Look up the name.  */
        else
@@ -2988,7 +2993,7 @@ cp_parser_primary_expression (cp_parser *parser,
 
            decl = cp_parser_lookup_name (parser, id_expression,
                                          none_type,
-                                         /*is_template=*/false,
+                                         template_p,
                                          /*is_namespace=*/false,
                                          /*check_dependency=*/true,
                                          &ambiguous_p);
@@ -3002,14 +3007,9 @@ cp_parser_primary_expression (cp_parser *parser,
            decl = objc_lookup_ivar (decl, id_expression);
 
            /* If name lookup gives us a SCOPE_REF, then the
-              qualifying scope was dependent.  Just propagate the
-              name.  */
+              qualifying scope was dependent.  */
            if (TREE_CODE (decl) == SCOPE_REF)
-             {
-               if (TYPE_P (TREE_OPERAND (decl, 0)))
-                 *qualifying_class = TREE_OPERAND (decl, 0);
-               return decl;
-             }
+             return decl;
            /* Check to see if DECL is a local variable in a context
               where that is forbidden.  */
            if (parser->local_variables_forbidden_p
@@ -3038,12 +3038,15 @@ cp_parser_primary_expression (cp_parser *parser,
              }
          }
 
-       decl = finish_id_expression (id_expression, decl, parser->scope,
-                                    idk, qualifying_class,
-                                    parser->integral_constant_expression_p,
-                                    parser->allow_non_integral_constant_expression_p,
-                                    &parser->non_integral_constant_expression_p,
-                                    &error_msg);
+       decl = (finish_id_expression 
+               (id_expression, decl, parser->scope,
+                idk,
+                parser->integral_constant_expression_p,
+                parser->allow_non_integral_constant_expression_p,
+                &parser->non_integral_constant_expression_p,
+                template_p, done, address_p,
+                template_arg_p,
+                &error_msg));
        if (error_msg)
          cp_parser_error (parser, error_msg);
        return decl;
@@ -3107,7 +3110,7 @@ cp_parser_id_expression (cp_parser *parser,
 
   /* Assume the `template' keyword was not used.  */
   if (template_p)
-    *template_p = false;
+    *template_p = template_keyword_p;
 
   /* Look for the optional `::' operator.  */
   global_scope_p
@@ -3627,23 +3630,36 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
            }
          break;
        }
-
       /* We've found one valid nested-name-specifier.  */
       success = true;
-      /* Make sure we look in the right scope the next time through
-        the loop.  */
-      parser->scope = (TREE_CODE (new_scope) == TYPE_DECL
-                      ? TREE_TYPE (new_scope)
-                      : new_scope);
+      /* Name lookup always gives us a DECL.  */
+      if (TREE_CODE (new_scope) == TYPE_DECL)
+       new_scope = TREE_TYPE (new_scope);
+      /* Uses of "template" must be followed by actual templates.  */
+      if (template_keyword_p
+         && !(CLASS_TYPE_P (new_scope)
+              && ((CLASSTYPE_USE_TEMPLATE (new_scope)
+                   && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (new_scope)))
+                  || CLASSTYPE_IS_TEMPLATE (new_scope)))
+         && !(TREE_CODE (new_scope) == TYPENAME_TYPE
+              && (TREE_CODE (TYPENAME_TYPE_FULLNAME (new_scope))
+                  == TEMPLATE_ID_EXPR)))
+       pedwarn (TYPE_P (new_scope)
+                ? "%qT is not a template"
+                : "%qD is not a template",
+                new_scope);
       /* If it is a class scope, try to complete it; we are about to
         be looking up names inside the class.  */
-      if (TYPE_P (parser->scope)
+      if (TYPE_P (new_scope)
          /* Since checking types for dependency can be expensive,
             avoid doing it if the type is already complete.  */
-         && !COMPLETE_TYPE_P (parser->scope)
+         && !COMPLETE_TYPE_P (new_scope)
          /* Do not try to complete dependent types.  */
-         && !dependent_type_p (parser->scope))
-       complete_type (parser->scope);
+         && !dependent_type_p (new_scope))
+       new_scope = complete_type (new_scope);
+      /* Make sure we look in the right scope the next time through
+        the loop.  */
+      parser->scope = new_scope;
     }
 
   /* Retrieve any deferred checks.  Do not pop this access checks yet
@@ -3818,10 +3834,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
   enum rid keyword;
   cp_id_kind idk = CP_ID_KIND_NONE;
   tree postfix_expression = NULL_TREE;
-  /* Non-NULL only if the current postfix-expression can be used to
-     form a pointer-to-member.  In that case, QUALIFYING_CLASS is the
-     class used to qualify the member.  */
-  tree qualifying_class = NULL_TREE;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -4073,38 +4085,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
          }
 
        /* It must be a primary-expression.  */
-       postfix_expression = cp_parser_primary_expression (parser,
-                                                          cast_p,
-                                                          &idk,
-                                                          &qualifying_class);
+       postfix_expression 
+         = cp_parser_primary_expression (parser, address_p, cast_p, 
+                                         /*template_arg_p=*/false,
+                                         &idk);
       }
       break;
     }
 
-  /* If we were avoiding committing to the processing of a
-     qualified-id until we knew whether or not we had a
-     pointer-to-member, we now know.  */
-  if (qualifying_class)
-    {
-      bool done;
-
-      /* Peek at the next token.  */
-      token = cp_lexer_peek_token (parser->lexer);
-      done = (token->type != CPP_OPEN_SQUARE
-             && token->type != CPP_OPEN_PAREN
-             && token->type != CPP_DOT
-             && token->type != CPP_DEREF
-             && token->type != CPP_PLUS_PLUS
-             && token->type != CPP_MINUS_MINUS);
-
-      postfix_expression = finish_qualified_id_expr (qualifying_class,
-                                                    postfix_expression,
-                                                    done,
-                                                    address_p);
-      if (done)
-       return postfix_expression;
-    }
-
   /* Keep looping until the postfix-expression is complete.  */
   while (true)
     {
@@ -4392,7 +4380,6 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
 {
   tree name;
   bool dependent_p;
-  bool template_p;
   bool pseudo_destructor_p;
   tree scope = NULL_TREE;
 
@@ -4463,12 +4450,14 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
       /* If the SCOPE is not a scalar type, we are looking at an
         ordinary class member access expression, rather than a
         pseudo-destructor-name.  */
-      template_p = cp_parser_optional_template_keyword (parser);
+      bool template_p;
       /* Parse the id-expression.  */
-      name = cp_parser_id_expression (parser, template_p,
-                                     /*check_dependency_p=*/true,
-                                     /*template_p=*/NULL,
-                                     /*declarator_p=*/false);
+      name = (cp_parser_id_expression 
+             (parser, 
+              cp_parser_optional_template_keyword (parser),
+              /*check_dependency_p=*/true,
+              &template_p,
+              /*declarator_p=*/false));
       /* In general, build a SCOPE_REF if the member name is qualified.
         However, if the name was not dependent and has already been
         resolved; there is no need to build the SCOPE_REF.  For example;
@@ -4495,7 +4484,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
        {
          if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
            {
-             name = build_nt (SCOPE_REF, parser->scope, name);
+             name = build_qualified_name (/*type=*/NULL_TREE,
+                                          parser->scope,
+                                          name,
+                                          template_p);
              parser->scope = NULL_TREE;
              parser->qualifying_scope = NULL_TREE;
              parser->object_scope = NULL_TREE;
@@ -4504,7 +4496,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
            adjust_result_of_qualified_name_lookup
              (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
          postfix_expression
-           = finish_class_member_access_expr (postfix_expression, name);
+           = finish_class_member_access_expr (postfix_expression, name,
+                                              template_p);
        }
     }
 
@@ -8917,6 +8910,7 @@ cp_parser_template_argument_list (cp_parser* parser)
   parser->integral_constant_expression_p = false;
   saved_non_ice_p = parser->non_integral_constant_expression_p;
   parser->non_integral_constant_expression_p = false;
+  /* Parse the arguments.  */
   do
     {
       tree argument;
@@ -8981,7 +8975,6 @@ cp_parser_template_argument (cp_parser* parser)
   bool maybe_type_id = false;
   cp_token *token;
   cp_id_kind idk;
-  tree qualifying_class;
 
   /* There's really no way to know what we're looking at, so we just
      try each alternative in order.
@@ -9073,9 +9066,10 @@ cp_parser_template_argument (cp_parser* parser)
     {
       cp_parser_parse_tentatively (parser);
       argument = cp_parser_primary_expression (parser,
+                                              /*adress_p=*/false,
                                               /*cast_p=*/false,
-                                              &idk,
-                                              &qualifying_class);
+                                              /*template_arg_p=*/true,
+                                              &idk);
       if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
          || !cp_parser_next_token_ends_template_argument_p (parser))
        cp_parser_simulate_error (parser);
@@ -9098,9 +9092,10 @@ cp_parser_template_argument (cp_parser* parser)
     {
       cp_parser_parse_tentatively (parser);
       argument = cp_parser_primary_expression (parser,
+                                              address_p,
                                               /*cast_p=*/false,
-                                              &idk,
-                                              &qualifying_class);
+                                              /*template_arg_p=*/true,
+                                              &idk);
       if (cp_parser_error_occurred (parser)
          || !cp_parser_next_token_ends_template_argument_p (parser))
        cp_parser_abort_tentative_parse (parser);
@@ -9112,16 +9107,7 @@ cp_parser_template_argument (cp_parser* parser)
              argument = TREE_OPERAND (argument, 0);
            }
 
-         /* If ADDRESS_P, then we use finish_qualified_id_expr so
-            that we get a pointer-to-member, if appropriate.
-            However, if ADDRESS_P is false, we don't want to turn
-            "T::f" into "(*this).T::f".  */
-         if (qualifying_class && address_p)
-           argument = finish_qualified_id_expr (qualifying_class,
-                                                argument,
-                                                /*done=*/true,
-                                                /*address_p=*/true);
-         else if (TREE_CODE (argument) == BASELINK)
+         if (TREE_CODE (argument) == BASELINK)
            /* We don't need the information about what class was used
               to name the overloaded functions.  */  
            argument = BASELINK_FUNCTIONS (argument);
@@ -14480,7 +14466,8 @@ cp_parser_label_declaration (cp_parser* parser)
 static tree
 cp_parser_lookup_name (cp_parser *parser, tree name,
                       enum tag_types tag_type,
-                      bool is_template, bool is_namespace,
+                      bool is_template, 
+                      bool is_namespace,
                       bool check_dependency,
                       bool *ambiguous_p)
 {
@@ -14575,12 +14562,17 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
                                         /*complain=*/1);
              decl = TYPE_NAME (type);
            }
-         else if (is_template)
+         else if (is_template
+                  && (cp_parser_next_token_ends_template_argument_p (parser)
+                      || cp_lexer_next_token_is (parser->lexer,
+                                                 CPP_CLOSE_PAREN)))
            decl = make_unbound_class_template (parser->scope,
                                                name, NULL_TREE,
                                                /*complain=*/1);
          else
-           decl = build_nt (SCOPE_REF, parser->scope, name);
+           decl = build_qualified_name (/*type=*/NULL_TREE,
+                                        parser->scope, name,
+                                        is_template);
        }
       else
        {
index 4d93724927acc7bfc845330ef756bbf6c4cf7906..1ef5669a82dbc08f7c028d5ba8b440eac17f0ada 100644 (file)
@@ -7544,7 +7544,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        if (e1 == error_mark_node || e2 == error_mark_node)
          return error_mark_node;
 
-       return build_nt (TREE_CODE (t), e1, e2);
+       return build_qualified_name (/*type=*/NULL_TREE,
+                                    e1, e2, QUALIFIED_NAME_IS_TEMPLATE (t));
       }
 
     case TYPEOF_TYPE:
@@ -7675,7 +7676,9 @@ tsubst_qualified_id (tree qualified_id, tree args,
     expr = name;
 
   if (dependent_type_p (scope))
-    return build_nt (SCOPE_REF, scope, expr);
+    return build_qualified_name (/*type=*/NULL_TREE, 
+                                scope, expr, 
+                                QUALIFIED_NAME_IS_TEMPLATE (qualified_id));
 
   if (!BASELINK_P (name) && !DECL_P (expr))
     {
@@ -7725,7 +7728,10 @@ tsubst_qualified_id (tree qualified_id, tree args,
     {
       expr = (adjust_result_of_qualified_name_lookup
              (expr, scope, current_class_type));
-      expr = finish_qualified_id_expr (scope, expr, done, address_p);
+      expr = (finish_qualified_id_expr 
+             (scope, expr, done, address_p,
+              QUALIFIED_NAME_IS_TEMPLATE (qualified_id),
+              /*template_arg_p=*/false));
     }
 
   if (TREE_CODE (expr) != SCOPE_REF)
@@ -7912,7 +7918,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
            name = tsubst_copy (TREE_OPERAND (name, 0), args,
                                complain, in_decl);
            name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
-           name = build_nt (SCOPE_REF, base, name);
+           name = build_qualified_name (/*type=*/NULL_TREE,
+                                        base, name, 
+                                        /*template_p=*/false);
          }
        else if (TREE_CODE (name) == BASELINK)
          name = tsubst_baselink (name,
@@ -7954,7 +7962,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case LT_EXPR:
     case GT_EXPR:
     case COMPOUND_EXPR:
-    case SCOPE_REF:
     case DOTSTAR_EXPR:
     case MEMBER_REF:
     case PREDECREMENT_EXPR:
@@ -7965,6 +7972,14 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        (code, tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl),
         tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl));
 
+    case SCOPE_REF:
+      return build_qualified_name (/*type=*/NULL_TREE,
+                                  tsubst_copy (TREE_OPERAND (t, 0),
+                                               args, complain, in_decl),
+                                  tsubst_copy (TREE_OPERAND (t, 1),
+                                               args, complain, in_decl),
+                                  QUALIFIED_NAME_IS_TEMPLATE (t));
+
     case ARRAY_REF:
       return build_nt
        (ARRAY_REF,
@@ -8438,7 +8453,6 @@ tsubst_copy_and_build (tree t,
       {
        tree decl;
        cp_id_kind idk;
-       tree qualifying_class;
        bool non_integral_constant_expression_p;
        const char *error_msg;
 
@@ -8458,10 +8472,13 @@ tsubst_copy_and_build (tree t,
 
        decl = finish_id_expression (t, decl, NULL_TREE,
                                     &idk,
-                                    &qualifying_class,
                                     /*integral_constant_expression_p=*/false,
                                     /*allow_non_integral_constant_expression_p=*/false,
                                     &non_integral_constant_expression_p,
+                                    /*template_p=*/false,
+                                    /*done=*/true,
+                                    /*address_p=*/false,
+                                    /*template_arg_p=*/false,
                                     &error_msg);
        if (error_msg)
          error (error_msg);
@@ -8872,7 +8889,8 @@ tsubst_copy_and_build (tree t,
        else if (TREE_CODE (member) == FIELD_DECL)
          return finish_non_static_data_member (member, object, NULL_TREE);
 
-       return finish_class_member_access_expr (object, member);
+       return finish_class_member_access_expr (object, member,
+                                               /*template_p=*/false);
       }
 
     case THROW_EXPR:
index d870fda6ba2c12ba5ac5871834b41412ec2a575d..5ccc7c757096742a80a577a27fba0909fdd965c3 100644 (file)
@@ -1407,8 +1407,10 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
         QUALIFYING_SCOPE is also non-null.  Wrap this in a SCOPE_REF
         for now.  */
       if (processing_template_decl)
-       return build_min (SCOPE_REF, TREE_TYPE (decl),
-                         qualifying_scope, DECL_NAME (decl));
+       return build_qualified_name (TREE_TYPE (decl),
+                                    qualifying_scope,
+                                    DECL_NAME (decl),
+                                    /*template_p=*/false);
 
       perform_or_defer_access_check (TYPE_BINFO (access_type), decl);
 
@@ -1494,15 +1496,24 @@ check_accessibility_of_qualified_id (tree decl,
    class named to the left of the "::" operator.  DONE is true if this
    expression is a complete postfix-expression; it is false if this
    expression is followed by '->', '[', '(', etc.  ADDRESS_P is true
-   iff this expression is the operand of '&'.  */
+   iff this expression is the operand of '&'.  TEMPLATE_P is true iff
+   the qualified-id was of the form "A::template B".  TEMPLATE_ARG_P
+   is true iff this qualified name appears as a template argument.  */
 
 tree
-finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
-                         bool address_p)
+finish_qualified_id_expr (tree qualifying_class, 
+                         tree expr, 
+                         bool done,
+                         bool address_p, 
+                         bool template_p,
+                         bool template_arg_p)
 {
   if (error_operand_p (expr))
     return error_mark_node;
 
+  if (template_p)
+    check_template_keyword (expr);
+
   /* If EXPR occurs as the operand of '&', use special handling that
      permits a pointer-to-member.  */
   if (address_p && done)
@@ -1514,7 +1525,13 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
       return expr;
     }
 
-  if (TREE_CODE (expr) == FIELD_DECL)
+  /* Within the scope of a class, turn references to non-static
+     members into expression of the form "this->...".  */
+  if (template_arg_p)
+    /* But, within a template argument, we do not want make the
+       transformation, as there is no "this" pointer.  */
+    ;
+  else if (TREE_CODE (expr) == FIELD_DECL)
     expr = finish_non_static_data_member (expr, current_class_ref,
                                          qualifying_class);
   else if (BASELINK_P (expr) && !processing_template_decl)
@@ -2383,6 +2400,13 @@ qualified_name_lookup_error (tree scope, tree name, tree decl)
    constant-expression, but a non-constant expression is also
    permissible.
 
+   DONE is true if this expression is a complete postfix-expression;
+   it is false if this expression is followed by '->', '[', '(', etc.
+   ADDRESS_P is true iff this expression is the operand of '&'.
+   TEMPLATE_P is true iff the qualified-id was of the form
+   "A::template B".  TEMPLATE_ARG_P is true iff this qualified name
+   appears as a template argument.
+
    If an error occurs, and it is the kind of error that might cause
    the parser to abort a tentative parse, *ERROR_MSG is filled in.  It
    is the caller's responsibility to issue the message.  *ERROR_MSG
@@ -2401,10 +2425,13 @@ finish_id_expression (tree id_expression,
                      tree decl,
                      tree scope,
                      cp_id_kind *idk,
-                     tree *qualifying_class,
                      bool integral_constant_expression_p,
                      bool allow_non_integral_constant_expression_p,
                      bool *non_integral_constant_expression_p,
+                     bool template_p,
+                     bool done,
+                     bool address_p,
+                     bool template_arg_p,
                      const char **error_msg)
 {
   /* Initialize the output parameters.  */
@@ -2610,20 +2637,32 @@ finish_id_expression (tree id_expression,
             dependent.  */
          if (scope)
            {
-             if (TYPE_P (scope))
-               *qualifying_class = scope;
              /* Since this name was dependent, the expression isn't
                 constant -- yet.  No error is issued because it might
                 be constant when things are instantiated.  */
              if (integral_constant_expression_p)
                *non_integral_constant_expression_p = true;
-             if (TYPE_P (scope) && dependent_type_p (scope))
-               return build_nt (SCOPE_REF, scope, id_expression);
-             else if (TYPE_P (scope) && DECL_P (decl))
-               return convert_from_reference
-                 (build2 (SCOPE_REF, TREE_TYPE (decl), scope, id_expression));
-             else
-               return convert_from_reference (decl);
+             if (TYPE_P (scope))
+               {
+                 if (address_p && done)
+                   decl = finish_qualified_id_expr (scope, decl,
+                                                    done, address_p,
+                                                    template_p,
+                                                    template_arg_p);
+                 else if (dependent_type_p (scope))
+                   decl = build_qualified_name (/*type=*/NULL_TREE,
+                                                scope,
+                                                id_expression,
+                                                template_p);
+                 else if (DECL_P (decl))
+                   decl = build_qualified_name (TREE_TYPE (decl),
+                                                scope,
+                                                id_expression,
+                                                template_p);
+               }
+             if (TREE_TYPE (decl))
+               decl = convert_from_reference (decl);
+             return decl;
            }
          /* A TEMPLATE_ID already contains all the information we
             need.  */
@@ -2703,14 +2742,20 @@ finish_id_expression (tree id_expression,
            mark_used (decl);
 
          if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
-           *qualifying_class = scope;
+           decl = finish_qualified_id_expr (scope,
+                                            decl,
+                                            done,
+                                            address_p,
+                                            template_p,
+                                            template_arg_p);
          else
            {
              tree r = convert_from_reference (decl);
 
-             if (processing_template_decl
-                 && TYPE_P (scope))
-               r = build2 (SCOPE_REF, TREE_TYPE (r), scope, decl);
+             if (processing_template_decl && TYPE_P (scope))
+               r = build_qualified_name (TREE_TYPE (r),
+                                         scope, decl,
+                                         template_p);
              decl = r;
            }
        }
@@ -2734,13 +2779,15 @@ finish_id_expression (tree id_expression,
          if (!really_overloaded_fn (decl))
            mark_used (first_fn);
 
-         if (TREE_CODE (first_fn) == FUNCTION_DECL
+         if (!template_arg_p
+             && TREE_CODE (first_fn) == FUNCTION_DECL
              && DECL_FUNCTION_MEMBER_P (first_fn)
              && !shared_member_p (decl))
            {
              /* A set of member functions.  */
              decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
-             return finish_class_member_access_expr (decl, id_expression);
+             return finish_class_member_access_expr (decl, id_expression,
+                                                     /*template_p=*/false);
            }
        }
       else
index 954a8093a9599bc53a1af91d4e145785b9d39538..15ee56c7c870da81be2e95de7d0b4bd44c6eb30a 100644 (file)
@@ -805,6 +805,23 @@ debug_binfo (tree elem)
     }
 }
 
+/* Build a representation for the qualified name SCOPE::NAME.  TYPE is
+   the type of the result expression, if known, or NULL_TREE if the
+   resulting expression is type-dependent.  If TEMPLATE_P is true,
+   NAME is known to be a template because the user explicitly used the
+   "template" keyword after the "::".   
+
+   All SCOPE_REFs should be built by use of this function.  */
+
+tree
+build_qualified_name (tree type, tree scope, tree name, bool template_p)
+{
+  tree t;
+  t = build2 (SCOPE_REF, type, scope, name);
+  QUALIFIED_NAME_IS_TEMPLATE (t) = template_p;
+  return t;
+}
+
 int
 is_overloaded_fn (tree x)
 {
index d39b53ae967b2c1583979446bd8a644db94cbc7e..bc34a40380688146fb6730af72961eaeda890c8f 100644 (file)
@@ -1841,16 +1841,69 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
   return expr;
 }
 
+/* An expression of the form "A::template B" has been resolved to
+   DECL.  Issue a diagnostic if B is not a template or template
+   specialization.  */
+
+void
+check_template_keyword (tree decl)
+{
+  /* The standard says:
+
+      [temp.names]
+
+      If a name prefixed by the keyword template is not a member
+      template, the program is ill-formed.
+
+     DR 228 removed the restriction that the template be a member
+     template.  
+     
+     DR 96, if accepted would add the further restriction that explcit
+     template arguments must be provided if the template keyword is
+     used, but, as of 2005-10-16, that DR is still in "drafting".  If
+     this DR is accepted, then the semantic checks here can be
+     simplified, as the entity named must in fact be a template
+     specialization, rather than, as at present, a set of overloaded
+     functions containing at least one template function.  */
+  if (TREE_CODE (decl) != TEMPLATE_DECL
+      && TREE_CODE (decl) != TEMPLATE_ID_EXPR)
+    {
+      if (!is_overloaded_fn (decl))
+       pedwarn ("%qD is not a template", decl);
+      else
+       {
+         tree fns;
+         if (BASELINK_P (decl))
+           fns = BASELINK_FUNCTIONS (decl);
+         while (fns)
+           {
+             tree fn = OVL_CURRENT (fns);
+             if (TREE_CODE (fn) == TEMPLATE_DECL
+                 || TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+               break;
+             if (TREE_CODE (fn) == FUNCTION_DECL
+                 && DECL_USE_TEMPLATE (fn)
+                 && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
+               break;
+             fns = OVL_NEXT (fns);
+           }
+         if (!fns)
+           pedwarn ("%qD is not a template", decl);
+       }
+    }
+}
+
 /* This function is called by the parser to process a class member
    access expression of the form OBJECT.NAME.  NAME is a node used by
    the parser to represent a name; it is not yet a DECL.  It may,
    however, be a BASELINK where the BASELINK_FUNCTIONS is a
    TEMPLATE_ID_EXPR.  Templates must be looked up by the parser, and
    there is no reason to do the lookup twice, so the parser keeps the
-   BASELINK.  */
+   BASELINK.  TEMPLATE_P is true iff NAME was explicitly declared to
+   be a template via the use of the "A::template B" syntax.  */
 
 tree
-finish_class_member_access_expr (tree object, tree name)
+finish_class_member_access_expr (tree object, tree name, bool template_p)
 {
   tree expr;
   tree object_type;
@@ -1995,6 +2048,9 @@ finish_class_member_access_expr (tree object, tree name)
   if (TREE_DEPRECATED (member))
     warn_deprecated_use (member);
 
+  if (template_p)
+    check_template_keyword (member);
+
   expr = build_class_member_access_expr (object, member, access_path,
                                         /*preserve_reference=*/false);
   if (processing_template_decl && expr != error_mark_node)
index 0d4bd73a578e5b3008f0ea66a222168b38620c24..bcfad3f8b99517924d251093b59617ef9f69bb01 100644 (file)
@@ -1,3 +1,9 @@
+2005-10-16  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/22137
+       * g++.dg/parse/template18.C: New test.
+       * g++.dg/template/nontype15.C: Likewise.
+
 2005-10-16  Erik Edelmann  <erik.edelmann@iki.fi>
 
        PR fortran/22273
diff --git a/gcc/testsuite/g++.dg/parse/template18.C b/gcc/testsuite/g++.dg/parse/template18.C
new file mode 100644 (file)
index 0000000..82336ab
--- /dev/null
@@ -0,0 +1,52 @@
+// PR c++/22137
+
+struct A
+{
+  static void a1();
+  template <typename T>
+  static void b1(T);
+  template <int I>
+  struct B {
+    static void b1();
+    template <typename T>
+    static void b2(T);
+  };
+  struct C {
+    static void c1();
+  };
+};
+
+template<int I> void f1()
+{
+  A* p;
+  A::template a1(); // { dg-error "template" }
+  A::template b1(0);
+  p->template a1(); // { dg-error "template" }
+  p->template b1('a');
+
+  A::template B<0>::b1();
+  A::template B<0>::template b1(); // { dg-error "template" }
+  A::template B<0>::template b2(0);
+  A::template B<0>::template b2<double>(0);
+
+  // Because B<I> is dependent, none of these are errors, as this
+  // function is not instantiated. 
+  A::template B<I>::b1();
+  A::template B<I>::template b1();
+  A::template B<I>::template b2(0);
+  A::template B<I>::template b2<double>(0);
+
+  A::template C::c1(); // { dg-error "template" }
+}
+
+template<int I> void f2()
+{
+  // These are copies of lines from f1, but this function is
+  // instantiated, so we should get errors here.
+  A::template B<I>::b1();
+  A::template B<I>::template b1(); // { dg-error "template" }
+  A::template B<I>::template b2(0);
+  A::template B<I>::template b2<double>(0);
+}
+
+template void f2<0>(); // { dg-error "instantiated" }
diff --git a/gcc/testsuite/g++.dg/template/nontype15.C b/gcc/testsuite/g++.dg/template/nontype15.C
new file mode 100644 (file)
index 0000000..dd5f4e7
--- /dev/null
@@ -0,0 +1,20 @@
+struct foo {
+    typedef int (*fun)(int);
+
+  static int f(int);    // overload between static & non-static
+  int f();
+
+  static int g(int);    // non-overloaded static
+};
+
+template<foo::fun>
+struct f_obj {
+  // something ..
+};
+
+int foo::f() {
+  f_obj<f> f1;
+  f_obj<g> f2;
+
+  return 0; 
+}