summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-29 11:16:50 +0000
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-29 11:16:50 +0000
commitb7edeb2322c878081a6542263dd698cfbd7b4136 (patch)
treef933bf28ffc6e8514814d1f5e3aab7549afff83b
parentf12876dd1718b4284363d55510a7b5d95605ab5a (diff)
downloadppe42-gcc-b7edeb2322c878081a6542263dd698cfbd7b4136.tar.gz
ppe42-gcc-b7edeb2322c878081a6542263dd698cfbd7b4136.zip
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69921 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog17
-rw-r--r--gcc/cp/decl.c106
-rw-r--r--gcc/cp/decl2.c2
-rw-r--r--gcc/cp/parser.c25
-rw-r--r--gcc/cp/pt.c11
-rw-r--r--gcc/cp/semantics.c4
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/template/using1.C42
-rw-r--r--gcc/testsuite/g++.dg/template/using2.C30
-rw-r--r--gcc/testsuite/g++.dg/template/using3.C42
-rw-r--r--gcc/testsuite/g++.dg/template/using4.C39
11 files changed, 259 insertions, 67 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 583d13ff584..12d843583f1 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,20 @@
+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>
PR c++/11530
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 583b8741744..637ad1f36d5 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -922,38 +922,37 @@ static int
add_binding (tree id, tree decl)
{
cxx_binding *binding = IDENTIFIER_BINDING (id);
+ tree bval = BINDING_VALUE (binding);
int ok = 1;
timevar_push (TV_NAME_LOOKUP);
if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
/* The new name is the type name. */
BINDING_TYPE (binding) = decl;
- else if (!BINDING_VALUE (binding))
+ else if (!bval)
/* This situation arises when push_class_level_binding moves an
inherited type-binding out of the way to make room for a new
value binding. */
BINDING_VALUE (binding) = decl;
- else if (TREE_CODE (BINDING_VALUE (binding)) == TYPE_DECL
- && DECL_ARTIFICIAL (BINDING_VALUE (binding)))
+ else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval))
{
/* The old binding was a type name. It was placed in
BINDING_VALUE because it was thought, at the point it was
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
binding. */
- BINDING_TYPE (binding) = BINDING_VALUE (binding);
+ BINDING_TYPE (binding) = bval;
BINDING_VALUE (binding) = decl;
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
- && DECL_NAME (decl) == DECL_NAME (BINDING_VALUE (binding))
- && (same_type_p (TREE_TYPE (decl),
- TREE_TYPE (BINDING_VALUE (binding)))
+ && DECL_NAME (decl) == DECL_NAME (bval)
+ && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval))
/* If either type involves template parameters, we must
wait until instantiation. */
|| 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
the same name. This is OK because of:
@@ -971,10 +970,8 @@ add_binding (tree id, tree decl)
A member shall not be declared twice in the
member-specification. */
- else if (TREE_CODE (decl) == VAR_DECL
- && TREE_CODE (BINDING_VALUE (binding)) == VAR_DECL
- && DECL_EXTERNAL (decl)
- && DECL_EXTERNAL (BINDING_VALUE (binding))
+ else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL
+ && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval)
&& !DECL_CLASS_SCOPE_P (decl))
{
duplicate_decls (decl, BINDING_VALUE (binding));
@@ -4273,47 +4270,54 @@ push_class_level_binding (tree name, tree x)
class, then we will need to restore IDENTIFIER_CLASS_VALUE when
we leave this class. Record the shadowed declaration here. */
binding = IDENTIFIER_BINDING (name);
- if (binding
- && ((TREE_CODE (x) == OVERLOAD
- && BINDING_VALUE (binding)
- && is_overloaded_fn (BINDING_VALUE (binding)))
- || INHERITED_VALUE_BINDING_P (binding)))
+ if (binding && BINDING_VALUE (binding))
{
- tree shadow;
- tree old_decl;
+ tree bval = BINDING_VALUE (binding);
+ tree old_decl = NULL_TREE;
- /* If the old binding was from a base class, and was for a tag
- name, slide it over to make room for the new binding. The
- old binding is still visible if explicitly qualified with a
- class-key. */
- if (INHERITED_VALUE_BINDING_P (binding)
- && BINDING_VALUE (binding)
- && TREE_CODE (BINDING_VALUE (binding)) == TYPE_DECL
- && DECL_ARTIFICIAL (BINDING_VALUE (binding))
- && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)))
- {
- old_decl = BINDING_TYPE (binding);
- BINDING_TYPE (binding) = BINDING_VALUE (binding);
- BINDING_VALUE (binding) = NULL_TREE;
- INHERITED_VALUE_BINDING_P (binding) = 0;
+ if (INHERITED_VALUE_BINDING_P (binding))
+ {
+ /* If the old binding was from a base class, and was for a
+ tag name, slide it over to make room for the new binding.
+ The old binding is still visible if explicitly qualified
+ with a class-key. */
+ if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval)
+ && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)))
+ {
+ BINDING_TYPE (binding) = bval;
+ 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
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 4a6e78d500f..896282c770d 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4126,7 +4126,7 @@ do_class_using_decl (tree decl)
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);
return value;
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 00f1c6eda4f..3aa684b3d2c 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -3483,18 +3483,19 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
parser->non_constant_expression_p = true;
}
- if (idk == CP_ID_KIND_UNQUALIFIED
- && (is_overloaded_fn (postfix_expression)
- || DECL_P (postfix_expression)
- || TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
- && args)
- postfix_expression
- = perform_koenig_lookup (postfix_expression, args);
- else if (idk == CP_ID_KIND_UNQUALIFIED
- && TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
- postfix_expression
- = unqualified_fn_lookup_error (postfix_expression);
-
+ if (idk == CP_ID_KIND_UNQUALIFIED)
+ {
+ if (args
+ && (is_overloaded_fn (postfix_expression)
+ || DECL_P (postfix_expression)
+ || TREE_CODE (postfix_expression) == IDENTIFIER_NODE))
+ postfix_expression
+ = perform_koenig_lookup (postfix_expression, args);
+ else if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
+ postfix_expression
+ = unqualified_fn_lookup_error (postfix_expression);
+ }
+
if (TREE_CODE (postfix_expression) == COMPONENT_REF)
{
tree instance = TREE_OPERAND (postfix_expression, 0);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8f10de49065..6966afdc8f5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6430,14 +6430,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
type = IDENTIFIER_TYPE_VALUE (t);
else
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
&& TREE_CODE (t) != TYPENAME_TYPE
&& TREE_CODE (t) != TEMPLATE_DECL
&& TREE_CODE (t) != IDENTIFIER_NODE
&& TREE_CODE (t) != FUNCTION_TYPE
+ && TREE_CODE (t) != USING_DECL
&& TREE_CODE (t) != METHOD_TYPE)
type = tsubst (type, args, complain, in_decl);
if (type == error_mark_node)
@@ -7907,6 +7909,9 @@ tsubst_copy_and_build (tree t,
switch (TREE_CODE (t))
{
+ case USING_DECL:
+ t = DECL_NAME (t);
+ /* Fallthrough. */
case IDENTIFIER_NODE:
{
tree decl;
@@ -11618,6 +11623,8 @@ type_dependent_expression_p (tree expression)
if (TREE_TYPE (expression) == unknown_type_node)
{
+ if (TREE_CODE (expression) == USING_DECL)
+ return true;
if (TREE_CODE (expression) == ADDR_EXPR)
return type_dependent_expression_p (TREE_OPERAND (expression, 0));
if (TREE_CODE (expression) == BASELINK)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index bf30ca08b8f..a94174ad945 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2030,7 +2030,9 @@ finish_member_declaration (tree decl)
/*friend_p=*/0);
}
/* 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
go at the beginning. The reason is that lookup_field_1
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b17dee5e091..520d8d0c2a7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+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>
* gcc.c-torture/execute/string-opt-9.c: strcmp returns int.
diff --git a/gcc/testsuite/g++.dg/template/using1.C b/gcc/testsuite/g++.dg/template/using1.C
new file mode 100644
index 00000000000..e4d4a004e32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/using1.C
@@ -0,0 +1,42 @@
+// { 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;
+}
+
diff --git a/gcc/testsuite/g++.dg/template/using2.C b/gcc/testsuite/g++.dg/template/using2.C
new file mode 100644
index 00000000000..87cdbc18657
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/using2.C
@@ -0,0 +1,30 @@
+// { 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" "" }
+}
+
diff --git a/gcc/testsuite/g++.dg/template/using3.C b/gcc/testsuite/g++.dg/template/using3.C
new file mode 100644
index 00000000000..11f2899c592
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/using3.C
@@ -0,0 +1,42 @@
+// { 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();
+}
diff --git a/gcc/testsuite/g++.dg/template/using4.C b/gcc/testsuite/g++.dg/template/using4.C
new file mode 100644
index 00000000000..8c46da464a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/using4.C
@@ -0,0 +1,39 @@
+// { 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();
+}
OpenPOWER on IntegriCloud