diff options
author | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-29 11:16:50 +0000 |
---|---|---|
committer | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-29 11:16:50 +0000 |
commit | b7edeb2322c878081a6542263dd698cfbd7b4136 (patch) | |
tree | f933bf28ffc6e8514814d1f5e3aab7549afff83b | |
parent | f12876dd1718b4284363d55510a7b5d95605ab5a (diff) | |
download | ppe42-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/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/cp/decl.c | 106 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 2 | ||||
-rw-r--r-- | gcc/cp/parser.c | 25 | ||||
-rw-r--r-- | gcc/cp/pt.c | 11 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/using1.C | 42 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/using2.C | 30 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/using3.C | 42 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/using4.C | 39 |
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(); +} |