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>
PR c++/21347
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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
......
......@@ -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:
......
......@@ -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
......
......@@ -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)
{
......
......@@ -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)
......
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
// 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