Commit 02ed62dd by Mark Mitchell Committed by Mark Mitchell

re PR c++/22137 (Internal error: Segmentation fault (program cc1plus))

	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
parent c2b27658
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> 2005-10-15 Mark Mitchell <mark@codesourcery.com>
PR c++/21347 PR c++/21347
......
...@@ -51,6 +51,7 @@ struct diagnostic_context; ...@@ -51,6 +51,7 @@ struct diagnostic_context;
BIND_EXPR_TRY_BLOCK (in BIND_EXPR) BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE)
REFERENCE_REF_P (in INDIRECT_EXPR) REFERENCE_REF_P (in INDIRECT_EXPR)
QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG. TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE. TEMPLATE_PARMS_FOR_INLINE.
...@@ -2933,6 +2934,11 @@ extern void decl_shadowed_for_var_insert (tree, tree); ...@@ -2933,6 +2934,11 @@ extern void decl_shadowed_for_var_insert (tree, tree);
#define THUNK_TARGET(NODE) \ #define THUNK_TARGET(NODE) \
(DECL_LANG_SPECIFIC (NODE)->u.f.befriending_classes) (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 /* These macros provide convenient access to the various _STMT nodes
created when parsing template declarations. */ created when parsing template declarations. */
#define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0) #define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0)
...@@ -4200,9 +4206,11 @@ extern tree finish_template_type (tree, tree, int); ...@@ -4200,9 +4206,11 @@ extern tree finish_template_type (tree, tree, int);
extern tree finish_base_specifier (tree, tree, bool); extern tree finish_base_specifier (tree, tree, bool);
extern void finish_member_declaration (tree); extern void finish_member_declaration (tree);
extern void qualified_name_lookup_error (tree, tree, tree); extern void qualified_name_lookup_error (tree, tree, tree);
extern void check_template_keyword (tree);
extern tree finish_id_expression (tree, tree, tree, extern tree finish_id_expression (tree, tree, tree,
cp_id_kind *, tree *, cp_id_kind *,
bool, bool, bool *, bool, bool, bool *,
bool, bool, bool, bool,
const char **); const char **);
extern tree finish_typeof (tree); extern tree finish_typeof (tree);
extern void finish_decl_cleanup (tree, tree); extern void finish_decl_cleanup (tree, tree);
...@@ -4212,7 +4220,8 @@ extern void finish_mem_initializers (tree); ...@@ -4212,7 +4220,8 @@ extern void finish_mem_initializers (tree);
extern tree check_template_template_default_arg (tree); extern tree check_template_template_default_arg (tree);
extern void expand_or_defer_fn (tree); extern void expand_or_defer_fn (tree);
extern void check_accessibility_of_qualified_id (tree, tree, 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 simplify_aggr_init_expr (tree *);
extern void finalize_nrv (tree *, tree, tree); extern void finalize_nrv (tree *, tree, tree);
extern void note_decl_for_pch (tree); extern void note_decl_for_pch (tree);
...@@ -4242,6 +4251,7 @@ extern tree get_target_expr (tree); ...@@ -4242,6 +4251,7 @@ extern tree get_target_expr (tree);
extern tree build_cplus_array_type (tree, tree); extern tree build_cplus_array_type (tree, tree);
extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_cons (tree, tree, tree);
extern tree hash_tree_chain (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 int is_overloaded_fn (tree);
extern tree get_first_fn (tree); extern tree get_first_fn (tree);
extern tree ovl_cons (tree, tree); extern tree ovl_cons (tree, tree);
...@@ -4305,7 +4315,7 @@ extern tree inline_conversion (tree); ...@@ -4305,7 +4315,7 @@ extern tree inline_conversion (tree);
extern tree decay_conversion (tree); extern tree decay_conversion (tree);
extern tree default_conversion (tree); extern tree default_conversion (tree);
extern tree build_class_member_access_expr (tree, tree, tree, bool); 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_x_indirect_ref (tree, const char *);
extern tree build_indirect_ref (tree, const char *); extern tree build_indirect_ref (tree, const char *);
extern tree build_array_ref (tree, tree); extern tree build_array_ref (tree, tree);
......
...@@ -1344,7 +1344,8 @@ build_offset_ref (tree type, tree name, bool address_p) ...@@ -1344,7 +1344,8 @@ build_offset_ref (tree type, tree name, bool address_p)
return name; return name;
if (dependent_type_p (type) || type_dependent_expression_p (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) if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{ {
......
...@@ -2008,9 +2008,10 @@ write_expression (tree expr) ...@@ -2008,9 +2008,10 @@ write_expression (tree expr)
if (code == PTRMEM_CST) if (code == PTRMEM_CST)
{ {
expr = build_nt (ADDR_EXPR, expr = build_nt (ADDR_EXPR,
build_nt (SCOPE_REF, build_qualified_name (/*type=*/NULL_TREE,
PTRMEM_CST_CLASS (expr), PTRMEM_CST_CLASS (expr),
PTRMEM_CST_MEMBER (expr))); PTRMEM_CST_MEMBER (expr),
/*template_p=*/false));
code = TREE_CODE (expr); code = TREE_CODE (expr);
} }
...@@ -2186,7 +2187,7 @@ write_expression (tree expr) ...@@ -2186,7 +2187,7 @@ write_expression (tree expr)
for (i = 0; i < TREE_CODE_LENGTH (code); ++i) for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
{ {
tree operand = TREE_OPERAND (expr, 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 conditional may be omitted. Since expression
manglings are supposed to represent the input token manglings are supposed to represent the input token
stream, there's no good way to mangle such an stream, there's no good way to mangle such an
......
...@@ -1381,7 +1381,7 @@ static bool cp_parser_translation_unit ...@@ -1381,7 +1381,7 @@ static bool cp_parser_translation_unit
/* Expressions [gram.expr] */ /* Expressions [gram.expr] */
static tree cp_parser_primary_expression 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 static tree cp_parser_id_expression
(cp_parser *, bool, bool, bool *, bool); (cp_parser *, bool, bool, bool *, bool);
static tree cp_parser_unqualified_id static tree cp_parser_unqualified_id
...@@ -2716,29 +2716,25 @@ cp_parser_translation_unit (cp_parser* parser) ...@@ -2716,29 +2716,25 @@ cp_parser_translation_unit (cp_parser* parser)
literal: literal:
__null __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. Returns a representation of the expression. Upon return, *IDK
indicates what kind of id-expression (if any) was present. */
*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. */
static tree static tree
cp_parser_primary_expression (cp_parser *parser, cp_parser_primary_expression (cp_parser *parser,
bool address_p,
bool cast_p, bool cast_p,
cp_id_kind *idk, bool template_arg_p,
tree *qualifying_class) cp_id_kind *idk)
{ {
cp_token *token; cp_token *token;
/* Assume the primary expression is not an id-expression. */ /* Assume the primary expression is not an id-expression. */
*idk = CP_ID_KIND_NONE; *idk = CP_ID_KIND_NONE;
/* And that it cannot be used as pointer-to-member. */
*qualifying_class = NULL_TREE;
/* Peek at the next token. */ /* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer);
...@@ -2964,6 +2960,8 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -2964,6 +2960,8 @@ cp_parser_primary_expression (cp_parser *parser,
tree id_expression; tree id_expression;
tree decl; tree decl;
const char *error_msg; const char *error_msg;
bool template_p;
bool done;
id_expression: id_expression:
/* Parse the id-expression. */ /* Parse the id-expression. */
...@@ -2971,14 +2969,21 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -2971,14 +2969,21 @@ cp_parser_primary_expression (cp_parser *parser,
= cp_parser_id_expression (parser, = cp_parser_id_expression (parser,
/*template_keyword_p=*/false, /*template_keyword_p=*/false,
/*check_dependency_p=*/true, /*check_dependency_p=*/true,
/*template_p=*/NULL, &template_p,
/*declarator_p=*/false); /*declarator_p=*/false);
if (id_expression == error_mark_node) if (id_expression == error_mark_node)
return 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 /* If we have a template-id, then no further lookup is
required. If the template-id was for a template-class, we required. If the template-id was for a template-class, we
will sometimes have a TYPE_DECL at this point. */ will sometimes have a TYPE_DECL at this point. */
else if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
|| TREE_CODE (id_expression) == TYPE_DECL) || TREE_CODE (id_expression) == TYPE_DECL)
decl = id_expression; decl = id_expression;
/* Look up the name. */ /* Look up the name. */
...@@ -2988,7 +2993,7 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -2988,7 +2993,7 @@ cp_parser_primary_expression (cp_parser *parser,
decl = cp_parser_lookup_name (parser, id_expression, decl = cp_parser_lookup_name (parser, id_expression,
none_type, none_type,
/*is_template=*/false, template_p,
/*is_namespace=*/false, /*is_namespace=*/false,
/*check_dependency=*/true, /*check_dependency=*/true,
&ambiguous_p); &ambiguous_p);
...@@ -3002,14 +3007,9 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -3002,14 +3007,9 @@ cp_parser_primary_expression (cp_parser *parser,
decl = objc_lookup_ivar (decl, id_expression); decl = objc_lookup_ivar (decl, id_expression);
/* If name lookup gives us a SCOPE_REF, then the /* If name lookup gives us a SCOPE_REF, then the
qualifying scope was dependent. Just propagate the qualifying scope was dependent. */
name. */
if (TREE_CODE (decl) == SCOPE_REF) 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 /* Check to see if DECL is a local variable in a context
where that is forbidden. */ where that is forbidden. */
if (parser->local_variables_forbidden_p if (parser->local_variables_forbidden_p
...@@ -3038,12 +3038,15 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -3038,12 +3038,15 @@ cp_parser_primary_expression (cp_parser *parser,
} }
} }
decl = finish_id_expression (id_expression, decl, parser->scope, decl = (finish_id_expression
idk, qualifying_class, (id_expression, decl, parser->scope,
idk,
parser->integral_constant_expression_p, parser->integral_constant_expression_p,
parser->allow_non_integral_constant_expression_p, parser->allow_non_integral_constant_expression_p,
&parser->non_integral_constant_expression_p, &parser->non_integral_constant_expression_p,
&error_msg); template_p, done, address_p,
template_arg_p,
&error_msg));
if (error_msg) if (error_msg)
cp_parser_error (parser, error_msg); cp_parser_error (parser, error_msg);
return decl; return decl;
...@@ -3107,7 +3110,7 @@ cp_parser_id_expression (cp_parser *parser, ...@@ -3107,7 +3110,7 @@ cp_parser_id_expression (cp_parser *parser,
/* Assume the `template' keyword was not used. */ /* Assume the `template' keyword was not used. */
if (template_p) if (template_p)
*template_p = false; *template_p = template_keyword_p;
/* Look for the optional `::' operator. */ /* Look for the optional `::' operator. */
global_scope_p global_scope_p
...@@ -3627,23 +3630,36 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, ...@@ -3627,23 +3630,36 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
} }
break; break;
} }
/* We've found one valid nested-name-specifier. */ /* We've found one valid nested-name-specifier. */
success = true; success = true;
/* Make sure we look in the right scope the next time through /* Name lookup always gives us a DECL. */
the loop. */ if (TREE_CODE (new_scope) == TYPE_DECL)
parser->scope = (TREE_CODE (new_scope) == TYPE_DECL new_scope = TREE_TYPE (new_scope);
? TREE_TYPE (new_scope) /* Uses of "template" must be followed by actual templates. */
: new_scope); 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 /* If it is a class scope, try to complete it; we are about to
be looking up names inside the class. */ 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, /* Since checking types for dependency can be expensive,
avoid doing it if the type is already complete. */ 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. */ /* Do not try to complete dependent types. */
&& !dependent_type_p (parser->scope)) && !dependent_type_p (new_scope))
complete_type (parser->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 /* 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) ...@@ -3818,10 +3834,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
enum rid keyword; enum rid keyword;
cp_id_kind idk = CP_ID_KIND_NONE; cp_id_kind idk = CP_ID_KIND_NONE;
tree postfix_expression = NULL_TREE; 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. */ /* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer); token = cp_lexer_peek_token (parser->lexer);
...@@ -4073,38 +4085,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) ...@@ -4073,38 +4085,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
} }
/* It must be a primary-expression. */ /* It must be a primary-expression. */
postfix_expression = cp_parser_primary_expression (parser, postfix_expression
cast_p, = cp_parser_primary_expression (parser, address_p, cast_p,
&idk, /*template_arg_p=*/false,
&qualifying_class); &idk);
} }
break; 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. */ /* Keep looping until the postfix-expression is complete. */
while (true) while (true)
{ {
...@@ -4392,7 +4380,6 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, ...@@ -4392,7 +4380,6 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
{ {
tree name; tree name;
bool dependent_p; bool dependent_p;
bool template_p;
bool pseudo_destructor_p; bool pseudo_destructor_p;
tree scope = NULL_TREE; tree scope = NULL_TREE;
...@@ -4463,12 +4450,14 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, ...@@ -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 /* If the SCOPE is not a scalar type, we are looking at an
ordinary class member access expression, rather than a ordinary class member access expression, rather than a
pseudo-destructor-name. */ pseudo-destructor-name. */
template_p = cp_parser_optional_template_keyword (parser); bool template_p;
/* Parse the id-expression. */ /* Parse the id-expression. */
name = cp_parser_id_expression (parser, template_p, name = (cp_parser_id_expression
(parser,
cp_parser_optional_template_keyword (parser),
/*check_dependency_p=*/true, /*check_dependency_p=*/true,
/*template_p=*/NULL, &template_p,
/*declarator_p=*/false); /*declarator_p=*/false));
/* In general, build a SCOPE_REF if the member name is qualified. /* In general, build a SCOPE_REF if the member name is qualified.
However, if the name was not dependent and has already been However, if the name was not dependent and has already been
resolved; there is no need to build the SCOPE_REF. For example; 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, ...@@ -4495,7 +4484,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
{ {
if (name != error_mark_node && !BASELINK_P (name) && parser->scope) 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->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE; parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE; parser->object_scope = NULL_TREE;
...@@ -4504,7 +4496,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, ...@@ -4504,7 +4496,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
adjust_result_of_qualified_name_lookup adjust_result_of_qualified_name_lookup
(name, BINFO_TYPE (BASELINK_BINFO (name)), scope); (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
postfix_expression 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) ...@@ -8917,6 +8910,7 @@ cp_parser_template_argument_list (cp_parser* parser)
parser->integral_constant_expression_p = false; parser->integral_constant_expression_p = false;
saved_non_ice_p = parser->non_integral_constant_expression_p; saved_non_ice_p = parser->non_integral_constant_expression_p;
parser->non_integral_constant_expression_p = false; parser->non_integral_constant_expression_p = false;
/* Parse the arguments. */
do do
{ {
tree argument; tree argument;
...@@ -8981,7 +8975,6 @@ cp_parser_template_argument (cp_parser* parser) ...@@ -8981,7 +8975,6 @@ cp_parser_template_argument (cp_parser* parser)
bool maybe_type_id = false; bool maybe_type_id = false;
cp_token *token; cp_token *token;
cp_id_kind idk; cp_id_kind idk;
tree qualifying_class;
/* There's really no way to know what we're looking at, so we just /* There's really no way to know what we're looking at, so we just
try each alternative in order. try each alternative in order.
...@@ -9073,9 +9066,10 @@ cp_parser_template_argument (cp_parser* parser) ...@@ -9073,9 +9066,10 @@ cp_parser_template_argument (cp_parser* parser)
{ {
cp_parser_parse_tentatively (parser); cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser, argument = cp_parser_primary_expression (parser,
/*adress_p=*/false,
/*cast_p=*/false, /*cast_p=*/false,
&idk, /*template_arg_p=*/true,
&qualifying_class); &idk);
if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
|| !cp_parser_next_token_ends_template_argument_p (parser)) || !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_simulate_error (parser); cp_parser_simulate_error (parser);
...@@ -9098,9 +9092,10 @@ cp_parser_template_argument (cp_parser* parser) ...@@ -9098,9 +9092,10 @@ cp_parser_template_argument (cp_parser* parser)
{ {
cp_parser_parse_tentatively (parser); cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser, argument = cp_parser_primary_expression (parser,
address_p,
/*cast_p=*/false, /*cast_p=*/false,
&idk, /*template_arg_p=*/true,
&qualifying_class); &idk);
if (cp_parser_error_occurred (parser) if (cp_parser_error_occurred (parser)
|| !cp_parser_next_token_ends_template_argument_p (parser)) || !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_abort_tentative_parse (parser); cp_parser_abort_tentative_parse (parser);
...@@ -9112,16 +9107,7 @@ cp_parser_template_argument (cp_parser* parser) ...@@ -9112,16 +9107,7 @@ cp_parser_template_argument (cp_parser* parser)
argument = TREE_OPERAND (argument, 0); argument = TREE_OPERAND (argument, 0);
} }
/* If ADDRESS_P, then we use finish_qualified_id_expr so if (TREE_CODE (argument) == BASELINK)
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)
/* We don't need the information about what class was used /* We don't need the information about what class was used
to name the overloaded functions. */ to name the overloaded functions. */
argument = BASELINK_FUNCTIONS (argument); argument = BASELINK_FUNCTIONS (argument);
...@@ -14480,7 +14466,8 @@ cp_parser_label_declaration (cp_parser* parser) ...@@ -14480,7 +14466,8 @@ cp_parser_label_declaration (cp_parser* parser)
static tree static tree
cp_parser_lookup_name (cp_parser *parser, tree name, cp_parser_lookup_name (cp_parser *parser, tree name,
enum tag_types tag_type, enum tag_types tag_type,
bool is_template, bool is_namespace, bool is_template,
bool is_namespace,
bool check_dependency, bool check_dependency,
bool *ambiguous_p) bool *ambiguous_p)
{ {
...@@ -14575,12 +14562,17 @@ cp_parser_lookup_name (cp_parser *parser, tree name, ...@@ -14575,12 +14562,17 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
/*complain=*/1); /*complain=*/1);
decl = TYPE_NAME (type); 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, decl = make_unbound_class_template (parser->scope,
name, NULL_TREE, name, NULL_TREE,
/*complain=*/1); /*complain=*/1);
else else
decl = build_nt (SCOPE_REF, parser->scope, name); decl = build_qualified_name (/*type=*/NULL_TREE,
parser->scope, name,
is_template);
} }
else else
{ {
......
...@@ -7544,7 +7544,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -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) if (e1 == error_mark_node || e2 == error_mark_node)
return 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: case TYPEOF_TYPE:
...@@ -7675,7 +7676,9 @@ tsubst_qualified_id (tree qualified_id, tree args, ...@@ -7675,7 +7676,9 @@ tsubst_qualified_id (tree qualified_id, tree args,
expr = name; expr = name;
if (dependent_type_p (scope)) 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)) if (!BASELINK_P (name) && !DECL_P (expr))
{ {
...@@ -7725,7 +7728,10 @@ tsubst_qualified_id (tree qualified_id, tree args, ...@@ -7725,7 +7728,10 @@ tsubst_qualified_id (tree qualified_id, tree args,
{ {
expr = (adjust_result_of_qualified_name_lookup expr = (adjust_result_of_qualified_name_lookup
(expr, scope, current_class_type)); (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) if (TREE_CODE (expr) != SCOPE_REF)
...@@ -7912,7 +7918,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -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, name = tsubst_copy (TREE_OPERAND (name, 0), args,
complain, in_decl); complain, in_decl);
name = build1 (BIT_NOT_EXPR, NULL_TREE, name); 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) else if (TREE_CODE (name) == BASELINK)
name = tsubst_baselink (name, name = tsubst_baselink (name,
...@@ -7954,7 +7962,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -7954,7 +7962,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case LT_EXPR: case LT_EXPR:
case GT_EXPR: case GT_EXPR:
case COMPOUND_EXPR: case COMPOUND_EXPR:
case SCOPE_REF:
case DOTSTAR_EXPR: case DOTSTAR_EXPR:
case MEMBER_REF: case MEMBER_REF:
case PREDECREMENT_EXPR: case PREDECREMENT_EXPR:
...@@ -7965,6 +7972,14 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -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), (code, tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl),
tsubst_copy (TREE_OPERAND (t, 1), 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: case ARRAY_REF:
return build_nt return build_nt
(ARRAY_REF, (ARRAY_REF,
...@@ -8438,7 +8453,6 @@ tsubst_copy_and_build (tree t, ...@@ -8438,7 +8453,6 @@ tsubst_copy_and_build (tree t,
{ {
tree decl; tree decl;
cp_id_kind idk; cp_id_kind idk;
tree qualifying_class;
bool non_integral_constant_expression_p; bool non_integral_constant_expression_p;
const char *error_msg; const char *error_msg;
...@@ -8458,10 +8472,13 @@ tsubst_copy_and_build (tree t, ...@@ -8458,10 +8472,13 @@ tsubst_copy_and_build (tree t,
decl = finish_id_expression (t, decl, NULL_TREE, decl = finish_id_expression (t, decl, NULL_TREE,
&idk, &idk,
&qualifying_class,
/*integral_constant_expression_p=*/false, /*integral_constant_expression_p=*/false,
/*allow_non_integral_constant_expression_p=*/false, /*allow_non_integral_constant_expression_p=*/false,
&non_integral_constant_expression_p, &non_integral_constant_expression_p,
/*template_p=*/false,
/*done=*/true,
/*address_p=*/false,
/*template_arg_p=*/false,
&error_msg); &error_msg);
if (error_msg) if (error_msg)
error (error_msg); error (error_msg);
...@@ -8872,7 +8889,8 @@ tsubst_copy_and_build (tree t, ...@@ -8872,7 +8889,8 @@ tsubst_copy_and_build (tree t,
else if (TREE_CODE (member) == FIELD_DECL) else if (TREE_CODE (member) == FIELD_DECL)
return finish_non_static_data_member (member, object, NULL_TREE); 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: case THROW_EXPR:
......
...@@ -1407,8 +1407,10 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) ...@@ -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 QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF
for now. */ for now. */
if (processing_template_decl) if (processing_template_decl)
return build_min (SCOPE_REF, TREE_TYPE (decl), return build_qualified_name (TREE_TYPE (decl),
qualifying_scope, DECL_NAME (decl)); qualifying_scope,
DECL_NAME (decl),
/*template_p=*/false);
perform_or_defer_access_check (TYPE_BINFO (access_type), decl); perform_or_defer_access_check (TYPE_BINFO (access_type), decl);
...@@ -1494,15 +1496,24 @@ check_accessibility_of_qualified_id (tree 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 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 a complete postfix-expression; it is false if this
expression is followed by '->', '[', '(', etc. ADDRESS_P is true 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 tree
finish_qualified_id_expr (tree qualifying_class, tree expr, bool done, finish_qualified_id_expr (tree qualifying_class,
bool address_p) tree expr,
bool done,
bool address_p,
bool template_p,
bool template_arg_p)
{ {
if (error_operand_p (expr)) if (error_operand_p (expr))
return error_mark_node; return error_mark_node;
if (template_p)
check_template_keyword (expr);
/* If EXPR occurs as the operand of '&', use special handling that /* If EXPR occurs as the operand of '&', use special handling that
permits a pointer-to-member. */ permits a pointer-to-member. */
if (address_p && done) if (address_p && done)
...@@ -1514,7 +1525,13 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done, ...@@ -1514,7 +1525,13 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
return expr; 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, expr = finish_non_static_data_member (expr, current_class_ref,
qualifying_class); qualifying_class);
else if (BASELINK_P (expr) && !processing_template_decl) else if (BASELINK_P (expr) && !processing_template_decl)
...@@ -2383,6 +2400,13 @@ qualified_name_lookup_error (tree scope, tree name, tree decl) ...@@ -2383,6 +2400,13 @@ qualified_name_lookup_error (tree scope, tree name, tree decl)
constant-expression, but a non-constant expression is also constant-expression, but a non-constant expression is also
permissible. 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 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 the parser to abort a tentative parse, *ERROR_MSG is filled in. It
is the caller's responsibility to issue the message. *ERROR_MSG is the caller's responsibility to issue the message. *ERROR_MSG
...@@ -2401,10 +2425,13 @@ finish_id_expression (tree id_expression, ...@@ -2401,10 +2425,13 @@ finish_id_expression (tree id_expression,
tree decl, tree decl,
tree scope, tree scope,
cp_id_kind *idk, cp_id_kind *idk,
tree *qualifying_class,
bool integral_constant_expression_p, bool integral_constant_expression_p,
bool allow_non_integral_constant_expression_p, bool allow_non_integral_constant_expression_p,
bool *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) const char **error_msg)
{ {
/* Initialize the output parameters. */ /* Initialize the output parameters. */
...@@ -2610,20 +2637,32 @@ finish_id_expression (tree id_expression, ...@@ -2610,20 +2637,32 @@ finish_id_expression (tree id_expression,
dependent. */ dependent. */
if (scope) if (scope)
{ {
if (TYPE_P (scope))
*qualifying_class = scope;
/* Since this name was dependent, the expression isn't /* Since this name was dependent, the expression isn't
constant -- yet. No error is issued because it might constant -- yet. No error is issued because it might
be constant when things are instantiated. */ be constant when things are instantiated. */
if (integral_constant_expression_p) if (integral_constant_expression_p)
*non_integral_constant_expression_p = true; *non_integral_constant_expression_p = true;
if (TYPE_P (scope) && dependent_type_p (scope)) if (TYPE_P (scope))
return build_nt (SCOPE_REF, scope, id_expression); {
else if (TYPE_P (scope) && DECL_P (decl)) if (address_p && done)
return convert_from_reference decl = finish_qualified_id_expr (scope, decl,
(build2 (SCOPE_REF, TREE_TYPE (decl), scope, id_expression)); done, address_p,
else template_p,
return convert_from_reference (decl); 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 /* A TEMPLATE_ID already contains all the information we
need. */ need. */
...@@ -2703,14 +2742,20 @@ finish_id_expression (tree id_expression, ...@@ -2703,14 +2742,20 @@ finish_id_expression (tree id_expression,
mark_used (decl); mark_used (decl);
if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (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 else
{ {
tree r = convert_from_reference (decl); tree r = convert_from_reference (decl);
if (processing_template_decl if (processing_template_decl && TYPE_P (scope))
&& TYPE_P (scope)) r = build_qualified_name (TREE_TYPE (r),
r = build2 (SCOPE_REF, TREE_TYPE (r), scope, decl); scope, decl,
template_p);
decl = r; decl = r;
} }
} }
...@@ -2734,13 +2779,15 @@ finish_id_expression (tree id_expression, ...@@ -2734,13 +2779,15 @@ finish_id_expression (tree id_expression,
if (!really_overloaded_fn (decl)) if (!really_overloaded_fn (decl))
mark_used (first_fn); 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) && DECL_FUNCTION_MEMBER_P (first_fn)
&& !shared_member_p (decl)) && !shared_member_p (decl))
{ {
/* A set of member functions. */ /* A set of member functions. */
decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0); 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 else
......
...@@ -805,6 +805,23 @@ debug_binfo (tree elem) ...@@ -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 int
is_overloaded_fn (tree x) is_overloaded_fn (tree x)
{ {
......
...@@ -1841,16 +1841,69 @@ lookup_destructor (tree object, tree scope, tree dtor_name) ...@@ -1841,16 +1841,69 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
return expr; 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 /* 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 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, the parser to represent a name; it is not yet a DECL. It may,
however, be a BASELINK where the BASELINK_FUNCTIONS is a however, be a BASELINK where the BASELINK_FUNCTIONS is a
TEMPLATE_ID_EXPR. Templates must be looked up by the parser, and 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 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 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 expr;
tree object_type; tree object_type;
...@@ -1995,6 +2048,9 @@ finish_class_member_access_expr (tree object, tree name) ...@@ -1995,6 +2048,9 @@ finish_class_member_access_expr (tree object, tree name)
if (TREE_DEPRECATED (member)) if (TREE_DEPRECATED (member))
warn_deprecated_use (member); warn_deprecated_use (member);
if (template_p)
check_template_keyword (member);
expr = build_class_member_access_expr (object, member, access_path, expr = build_class_member_access_expr (object, member, access_path,
/*preserve_reference=*/false); /*preserve_reference=*/false);
if (processing_template_decl && expr != error_mark_node) if (processing_template_decl && expr != error_mark_node)
......
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> 2005-10-16 Erik Edelmann <erik.edelmann@iki.fi>
PR fortran/22273 PR fortran/22273
// 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" }
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment