Commit 399dedb9 by Nathan Sidwell Committed by Nathan Sidwell

re PR c++/9447 (using Base<T>::member does not work)

cp:
	PR c++/9447
	* decl.c (add_binding): Add bval local variable.
	(push_class_level_binding): Likewise. Allow a USING_DECL to be
	pushed.
	* decl2.c (do_class_using_decl):  The type of a using decl is
	unknown.
	* parser.c (cp_parser_postfix_expression): Refactor unqualified-id
	function call lookup code.
	* pt.c (tsubst): A USING_DECL will have unknown type.
	(tsubst_copy_and_build): Allow a using decl.
	(type_dependent_expression_p): A USING_DECL will make it
	dependent.
	* semantics.c (finish_member_declaration): Push a dependent using
	declaration.
testsuite:
	PR c++/9447
	* g++.dg/template/using1.C: New test.
	* g++.dg/template/using2.C: New test.
	* g++.dg/template/using3.C: New test.
	* g++.dg/template/using4.C: New test.

From-SVN: r69921
parent 16ff3a23
2003-07-29 Nathan Sidwell <nathan@codesourcery.com>
PR c++/9447
* decl.c (add_binding): Add bval local variable.
(push_class_level_binding): Likewise. Allow a USING_DECL to be
pushed.
* decl2.c (do_class_using_decl): The type of a using decl is
unknown.
* parser.c (cp_parser_postfix_expression): Refactor unqualified-id
function call lookup code.
* pt.c (tsubst): A USING_DECL will have unknown type.
(tsubst_copy_and_build): Allow a using decl.
(type_dependent_expression_p): A USING_DECL will make it
dependent.
* semantics.c (finish_member_declaration): Push a dependent using
declaration.
2003-07-28 Mark Mitchell <mark@codesourcery.com> 2003-07-28 Mark Mitchell <mark@codesourcery.com>
PR c++/11530 PR c++/11530
......
...@@ -922,38 +922,37 @@ static int ...@@ -922,38 +922,37 @@ static int
add_binding (tree id, tree decl) add_binding (tree id, tree decl)
{ {
cxx_binding *binding = IDENTIFIER_BINDING (id); cxx_binding *binding = IDENTIFIER_BINDING (id);
tree bval = BINDING_VALUE (binding);
int ok = 1; int ok = 1;
timevar_push (TV_NAME_LOOKUP); timevar_push (TV_NAME_LOOKUP);
if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
/* The new name is the type name. */ /* The new name is the type name. */
BINDING_TYPE (binding) = decl; BINDING_TYPE (binding) = decl;
else if (!BINDING_VALUE (binding)) else if (!bval)
/* This situation arises when push_class_level_binding moves an /* This situation arises when push_class_level_binding moves an
inherited type-binding out of the way to make room for a new inherited type-binding out of the way to make room for a new
value binding. */ value binding. */
BINDING_VALUE (binding) = decl; BINDING_VALUE (binding) = decl;
else if (TREE_CODE (BINDING_VALUE (binding)) == TYPE_DECL else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval))
&& DECL_ARTIFICIAL (BINDING_VALUE (binding)))
{ {
/* The old binding was a type name. It was placed in /* The old binding was a type name. It was placed in
BINDING_VALUE because it was thought, at the point it was BINDING_VALUE because it was thought, at the point it was
declared, to be the only entity with such a name. Move the declared, to be the only entity with such a name. Move the
type name into the type slot; it is now hidden by the new type name into the type slot; it is now hidden by the new
binding. */ binding. */
BINDING_TYPE (binding) = BINDING_VALUE (binding); BINDING_TYPE (binding) = bval;
BINDING_VALUE (binding) = decl; BINDING_VALUE (binding) = decl;
INHERITED_VALUE_BINDING_P (binding) = 0; INHERITED_VALUE_BINDING_P (binding) = 0;
} }
else if (TREE_CODE (BINDING_VALUE (binding)) == TYPE_DECL else if (TREE_CODE (bval) == TYPE_DECL
&& TREE_CODE (decl) == TYPE_DECL && TREE_CODE (decl) == TYPE_DECL
&& DECL_NAME (decl) == DECL_NAME (BINDING_VALUE (binding)) && DECL_NAME (decl) == DECL_NAME (bval)
&& (same_type_p (TREE_TYPE (decl), && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval))
TREE_TYPE (BINDING_VALUE (binding)))
/* If either type involves template parameters, we must /* If either type involves template parameters, we must
wait until instantiation. */ wait until instantiation. */
|| uses_template_parms (TREE_TYPE (decl)) || uses_template_parms (TREE_TYPE (decl))
|| uses_template_parms (TREE_TYPE (BINDING_VALUE (binding))))) || uses_template_parms (TREE_TYPE (bval))))
/* We have two typedef-names, both naming the same type to have /* We have two typedef-names, both naming the same type to have
the same name. This is OK because of: the same name. This is OK because of:
...@@ -971,10 +970,8 @@ add_binding (tree id, tree decl) ...@@ -971,10 +970,8 @@ add_binding (tree id, tree decl)
A member shall not be declared twice in the A member shall not be declared twice in the
member-specification. */ member-specification. */
else if (TREE_CODE (decl) == VAR_DECL else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL
&& TREE_CODE (BINDING_VALUE (binding)) == VAR_DECL && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval)
&& DECL_EXTERNAL (decl)
&& DECL_EXTERNAL (BINDING_VALUE (binding))
&& !DECL_CLASS_SCOPE_P (decl)) && !DECL_CLASS_SCOPE_P (decl))
{ {
duplicate_decls (decl, BINDING_VALUE (binding)); duplicate_decls (decl, BINDING_VALUE (binding));
...@@ -4273,47 +4270,54 @@ push_class_level_binding (tree name, tree x) ...@@ -4273,47 +4270,54 @@ push_class_level_binding (tree name, tree x)
class, then we will need to restore IDENTIFIER_CLASS_VALUE when class, then we will need to restore IDENTIFIER_CLASS_VALUE when
we leave this class. Record the shadowed declaration here. */ we leave this class. Record the shadowed declaration here. */
binding = IDENTIFIER_BINDING (name); binding = IDENTIFIER_BINDING (name);
if (binding if (binding && BINDING_VALUE (binding))
&& ((TREE_CODE (x) == OVERLOAD
&& BINDING_VALUE (binding)
&& is_overloaded_fn (BINDING_VALUE (binding)))
|| INHERITED_VALUE_BINDING_P (binding)))
{ {
tree shadow; tree bval = BINDING_VALUE (binding);
tree old_decl; tree old_decl = NULL_TREE;
/* If the old binding was from a base class, and was for a tag if (INHERITED_VALUE_BINDING_P (binding))
name, slide it over to make room for the new binding. The {
old binding is still visible if explicitly qualified with a /* If the old binding was from a base class, and was for a
class-key. */ tag name, slide it over to make room for the new binding.
if (INHERITED_VALUE_BINDING_P (binding) The old binding is still visible if explicitly qualified
&& BINDING_VALUE (binding) with a class-key. */
&& TREE_CODE (BINDING_VALUE (binding)) == TYPE_DECL if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval)
&& DECL_ARTIFICIAL (BINDING_VALUE (binding)) && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)))
&& !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))) {
{ BINDING_TYPE (binding) = bval;
old_decl = BINDING_TYPE (binding); BINDING_VALUE (binding) = NULL_TREE;
BINDING_TYPE (binding) = BINDING_VALUE (binding); INHERITED_VALUE_BINDING_P (binding) = 0;
BINDING_VALUE (binding) = NULL_TREE; }
INHERITED_VALUE_BINDING_P (binding) = 0; old_decl = bval;
}
else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval))
old_decl = bval;
else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval))
old_decl = bval;
else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x))
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
if (old_decl)
{
tree shadow;
/* Find the previous binding of name on the class-shadowed
list, and update it. */
for (shadow = class_binding_level->class_shadowed;
shadow;
shadow = TREE_CHAIN (shadow))
if (TREE_PURPOSE (shadow) == name
&& TREE_TYPE (shadow) == old_decl)
{
BINDING_VALUE (binding) = x;
INHERITED_VALUE_BINDING_P (binding) = 0;
TREE_TYPE (shadow) = x;
IDENTIFIER_CLASS_VALUE (name) = x;
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
}
} }
else
old_decl = BINDING_VALUE (binding);
/* Find the previous binding of name on the class-shadowed
list, and update it. */
for (shadow = class_binding_level->class_shadowed;
shadow;
shadow = TREE_CHAIN (shadow))
if (TREE_PURPOSE (shadow) == name
&& TREE_TYPE (shadow) == old_decl)
{
BINDING_VALUE (binding) = x;
INHERITED_VALUE_BINDING_P (binding) = 0;
TREE_TYPE (shadow) = x;
IDENTIFIER_CLASS_VALUE (name) = x;
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
}
} }
/* If we didn't replace an existing binding, put the binding on the /* If we didn't replace an existing binding, put the binding on the
......
...@@ -4126,7 +4126,7 @@ do_class_using_decl (tree decl) ...@@ -4126,7 +4126,7 @@ do_class_using_decl (tree decl)
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 980716); my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 980716);
value = build_lang_decl (USING_DECL, name, void_type_node); value = build_lang_decl (USING_DECL, name, unknown_type_node);
DECL_INITIAL (value) = TREE_OPERAND (decl, 0); DECL_INITIAL (value) = TREE_OPERAND (decl, 0);
return value; return value;
} }
......
...@@ -3483,18 +3483,19 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) ...@@ -3483,18 +3483,19 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
parser->non_constant_expression_p = true; parser->non_constant_expression_p = true;
} }
if (idk == CP_ID_KIND_UNQUALIFIED if (idk == CP_ID_KIND_UNQUALIFIED)
&& (is_overloaded_fn (postfix_expression) {
|| DECL_P (postfix_expression) if (args
|| TREE_CODE (postfix_expression) == IDENTIFIER_NODE) && (is_overloaded_fn (postfix_expression)
&& args) || DECL_P (postfix_expression)
postfix_expression || TREE_CODE (postfix_expression) == IDENTIFIER_NODE))
= perform_koenig_lookup (postfix_expression, args); postfix_expression
else if (idk == CP_ID_KIND_UNQUALIFIED = perform_koenig_lookup (postfix_expression, args);
&& TREE_CODE (postfix_expression) == IDENTIFIER_NODE) else if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
postfix_expression postfix_expression
= unqualified_fn_lookup_error (postfix_expression); = unqualified_fn_lookup_error (postfix_expression);
}
if (TREE_CODE (postfix_expression) == COMPONENT_REF) if (TREE_CODE (postfix_expression) == COMPONENT_REF)
{ {
tree instance = TREE_OPERAND (postfix_expression, 0); tree instance = TREE_OPERAND (postfix_expression, 0);
......
...@@ -6430,14 +6430,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -6430,14 +6430,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
type = IDENTIFIER_TYPE_VALUE (t); type = IDENTIFIER_TYPE_VALUE (t);
else else
type = TREE_TYPE (t); type = TREE_TYPE (t);
if (type == unknown_type_node)
abort (); my_friendly_assert (type != unknown_type_node
|| TREE_CODE (t) == USING_DECL, 20030716);
if (type && TREE_CODE (t) != FUNCTION_DECL if (type && TREE_CODE (t) != FUNCTION_DECL
&& TREE_CODE (t) != TYPENAME_TYPE && TREE_CODE (t) != TYPENAME_TYPE
&& TREE_CODE (t) != TEMPLATE_DECL && TREE_CODE (t) != TEMPLATE_DECL
&& TREE_CODE (t) != IDENTIFIER_NODE && TREE_CODE (t) != IDENTIFIER_NODE
&& TREE_CODE (t) != FUNCTION_TYPE && TREE_CODE (t) != FUNCTION_TYPE
&& TREE_CODE (t) != USING_DECL
&& TREE_CODE (t) != METHOD_TYPE) && TREE_CODE (t) != METHOD_TYPE)
type = tsubst (type, args, complain, in_decl); type = tsubst (type, args, complain, in_decl);
if (type == error_mark_node) if (type == error_mark_node)
...@@ -7907,6 +7909,9 @@ tsubst_copy_and_build (tree t, ...@@ -7907,6 +7909,9 @@ tsubst_copy_and_build (tree t,
switch (TREE_CODE (t)) switch (TREE_CODE (t))
{ {
case USING_DECL:
t = DECL_NAME (t);
/* Fallthrough. */
case IDENTIFIER_NODE: case IDENTIFIER_NODE:
{ {
tree decl; tree decl;
...@@ -11618,6 +11623,8 @@ type_dependent_expression_p (tree expression) ...@@ -11618,6 +11623,8 @@ type_dependent_expression_p (tree expression)
if (TREE_TYPE (expression) == unknown_type_node) if (TREE_TYPE (expression) == unknown_type_node)
{ {
if (TREE_CODE (expression) == USING_DECL)
return true;
if (TREE_CODE (expression) == ADDR_EXPR) if (TREE_CODE (expression) == ADDR_EXPR)
return type_dependent_expression_p (TREE_OPERAND (expression, 0)); return type_dependent_expression_p (TREE_OPERAND (expression, 0));
if (TREE_CODE (expression) == BASELINK) if (TREE_CODE (expression) == BASELINK)
......
...@@ -2030,7 +2030,9 @@ finish_member_declaration (tree decl) ...@@ -2030,7 +2030,9 @@ finish_member_declaration (tree decl)
/*friend_p=*/0); /*friend_p=*/0);
} }
/* Enter the DECL into the scope of the class. */ /* Enter the DECL into the scope of the class. */
else if (TREE_CODE (decl) == USING_DECL || pushdecl_class_level (decl)) else if ((TREE_CODE (decl) == USING_DECL && !processing_template_decl
&& !dependent_type_p (DECL_INITIAL (decl)))
|| pushdecl_class_level (decl))
{ {
/* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields
go at the beginning. The reason is that lookup_field_1 go at the beginning. The reason is that lookup_field_1
......
2003-07-29 Nathan Sidwell <nathan@codesourcery.com>
PR c++/9447
* g++.dg/template/using1.C: New test.
* g++.dg/template/using2.C: New test.
* g++.dg/template/using3.C: New test.
* g++.dg/template/using4.C: New test.
2003-07-29 Alexandre Oliva <aoliva@redhat.com> 2003-07-29 Alexandre Oliva <aoliva@redhat.com>
* gcc.c-torture/execute/string-opt-9.c: strcmp returns int. * gcc.c-torture/execute/string-opt-9.c: strcmp returns int.
......
// { dg-do run }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 22 Jul 2003 <nathan@codesourcery.com>
// PR 9447. Using decls in template classes.
template <class T>
struct Foo {
int i;
};
struct Baz
{
int j;
};
template <class T>
struct Bar : public Foo<T>, Baz {
using Foo<T>::i;
using Baz::j;
int foo () { return i; }
int baz () { return j; }
};
int main()
{
Bar<int> bar;
bar.i = 1;
bar.j = 2;
if (bar.foo() != 1)
return 1;
if (bar.baz() != 2)
return 1;
return 0;
}
// { dg-do compile }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 22 Jul 2003 <nathan@codesourcery.com>
// PR 9447. Using decls in template classes.
template <class T>
struct Foo {
int i; // { dg-error "" "" }
};
struct Baz
{
int i; // { dg-error "" "" }
};
template <class T>
struct Bar : public Foo<T>, Baz {
using Foo<T>::i;
using Baz::i;
int foo () { return i; } // { dg-error "request for member" "" }
};
void foo (Bar<int> &bar)
{
bar.foo(); // { dg-error "instantiated" "" }
}
// { dg-do run }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 22 Jul 2003 <nathan@codesourcery.com>
// PR 9447. Using decls in template classes.
template <class T>
struct Foo {
int i (int) {return 1;}
};
struct Baz
{
int k (int) {return 2;}
};
template <class T>
struct Bar : public Foo<T> , Baz {
using Foo<T>::i;
using Baz::k;
int i (float) {return 3;}
int k (float) {return 3;}
int foo()
{
if (i (1) != 1)
return 1;
if (k (1) != 2)
return 2;
return 0;
}
};
int main()
{
Bar<int> bar;
return bar.foo();
}
// { dg-do run }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 22 Jul 2003 <nathan@codesourcery.com>
// PR 9447. Using decls in template classes.
template <class T>
struct Foo {
int k (float) {return 1;}
};
struct Baz
{
int k (int) {return 2;}
};
template <class T>
struct Bar : public Foo<T> , Baz {
using Foo<T>::k;
using Baz::k;
int foo()
{
if (k (1.0f) != 1)
return 1;
if (k (1) != 2)
return 2;
return 0;
}
};
int main()
{
Bar<int> bar;
return bar.foo();
}
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