From 5c44cef5f5610e48cce17e8d085636c18f308363 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 12 Nov 2019 21:21:13 +0000 Subject: [PATCH] [C++ PATCH] Merge some using-decl handling https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00971.html gcc/cp/ * name-lookup.c (lookup_using_decl): New function, merged from ... (do_class_using_decl): ... here. Call it. And ... (finish_nonmember_using_decl): ... here. Call it. gcc/testsuite/ * g++.dg/cpp0x/using-enum-2.C: Adjust expected error text. * g++.dg/cpp0x/using-enum-3.C: Likewise. * g++.dg/lookup/using4.C: Likewise. * g++.dg/lookup/using7.C: Likewise. * g++.dg/template/using12.C: Likewise. * g++.dg/template/using18.C: Likewise. * g++.dg/template/using22.C: Likewise. From-SVN: r278106 --- gcc/cp/ChangeLog | 12 +- gcc/cp/name-lookup.c | 244 +++++++++++++--------- gcc/testsuite/ChangeLog | 10 + gcc/testsuite/g++.dg/cpp0x/using-enum-2.C | 8 +- gcc/testsuite/g++.dg/cpp0x/using-enum-3.C | 2 +- gcc/testsuite/g++.dg/lookup/using4.C | 2 +- gcc/testsuite/g++.dg/lookup/using7.C | 1 - gcc/testsuite/g++.dg/template/using12.C | 2 +- gcc/testsuite/g++.dg/template/using18.C | 2 +- gcc/testsuite/g++.dg/template/using22.C | 8 +- 10 files changed, 172 insertions(+), 119 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3742e71fe3a..bf50b1bcfa9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-11-12 Nathan Sidwell + + * name-lookup.c (lookup_using_decl): New function, merged from ... + (do_class_using_decl): ... here. Call it. And ... + (finish_nonmember_using_decl): ... here. Call it. + 2019-11-12 Martin Liska * name-lookup.c: Do not include params.h. @@ -5,9 +11,9 @@ 2019-11-12 Martin Liska - * name-lookup.c (namespace_hints::namespace_hints): Replace old parameter syntax - with the new one, include opts.h if needed. Use SET_OPTION_IF_UNSET - macro. + * name-lookup.c (namespace_hints::namespace_hints): Replace old + parameter syntax with the new one, include opts.h if needed. Use + SET_OPTION_IF_UNSET macro. * typeck.c (comptypes): Likewise. 2019-11-12 Maciej W. Rozycki diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index d114c8873b2..b399b4ed39d 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4584,102 +4584,166 @@ push_class_level_binding (tree name, tree x) return ret; } -/* Process "using SCOPE::NAME" in a class scope. Return the - USING_DECL created. */ +/* Process and lookup a using decl SCOPE::lookup.name, filling in + lookup.values & lookup.type. Return true if ok. */ -tree -do_class_using_decl (tree scope, tree name) +static bool +lookup_using_decl (tree scope, name_lookup &lookup) { - if (name == error_mark_node) - return NULL_TREE; + tree current = current_scope (); + bool dependent_p = false; - if (!scope || !TYPE_P (scope)) + if (TREE_CODE (scope) == NAMESPACE_DECL) { - error ("using-declaration for non-member at class scope"); - return NULL_TREE; - } + /* Naming a namespace member. */ + if (TYPE_P (current)) + { + error ("using-declaration for non-member at class scope"); + return false; + } - /* Make sure the name is not invalid */ - if (TREE_CODE (name) == BIT_NOT_EXPR) - { - error ("%<%T::%D%> names destructor", scope, name); - return NULL_TREE; + qualified_namespace_lookup (scope, &lookup); } - - /* Using T::T declares inheriting ctors, even if T is a typedef. */ - if (MAYBE_CLASS_TYPE_P (scope) - && (name == TYPE_IDENTIFIER (scope) - || constructor_name_p (name, scope))) + else if (TREE_CODE (scope) == ENUMERAL_TYPE) { - maybe_warn_cpp0x (CPP0X_INHERITING_CTORS); - name = ctor_identifier; - CLASSTYPE_NON_AGGREGATE (current_class_type) = true; - TYPE_HAS_USER_CONSTRUCTOR (current_class_type) = true; + error ("using-declaration may not name enumerator %<%E::%D%>", + scope, lookup.name); + return false; } - - /* Cannot introduce a constructor name. */ - if (constructor_name_p (name, current_class_type)) + else { - error ("%<%T::%D%> names constructor in %qT", - scope, name, current_class_type); - return NULL_TREE; - } + /* Naming a class member. */ + if (!TYPE_P (current)) + { + error ("using-declaration for member at non-class scope"); + return false; + } - /* From [namespace.udecl]: + /* Make sure the name is not invalid */ + if (TREE_CODE (lookup.name) == BIT_NOT_EXPR) + { + error ("%<%T::%D%> names destructor", scope, lookup.name); + return false; + } - A using-declaration used as a member-declaration shall refer to a - member of a base class of the class being defined. + /* Using T::T declares inheriting ctors, even if T is a typedef. */ + if (MAYBE_CLASS_TYPE_P (scope) + && (lookup.name == TYPE_IDENTIFIER (scope) + || constructor_name_p (lookup.name, scope))) + { + maybe_warn_cpp0x (CPP0X_INHERITING_CTORS); + lookup.name = ctor_identifier; + CLASSTYPE_NON_AGGREGATE (current) = true; + TYPE_HAS_USER_CONSTRUCTOR (current) = true; + } + + /* Cannot introduce a constructor name. */ + if (constructor_name_p (lookup.name, current)) + { + error ("%<%T::%D%> names constructor in %qT", + scope, lookup.name, current); + return false; + } - In general, we cannot check this constraint in a template because - we do not know the entire set of base classes of the current - class type. Morover, if SCOPE is dependent, it might match a - non-dependent base. */ + /* Member using decls finish processing when completing the + class. */ + /* From [namespace.udecl]: - tree decl = NULL_TREE; - if (!dependent_scope_p (scope)) - { - base_kind b_kind; - tree binfo = lookup_base (current_class_type, scope, ba_any, &b_kind, - tf_warning_or_error); - if (b_kind < bk_proper_base) + A using-declaration used as a member-declaration shall refer + to a member of a base class of the class being defined. + + In general, we cannot check this constraint in a template + because we do not know the entire set of base classes of the + current class type. Morover, if SCOPE is dependent, it might + match a non-dependent base. */ + + dependent_p = dependent_scope_p (scope); + if (!dependent_p) { - /* If there are dependent bases, scope might resolve at - instantiation time, even if it isn't exactly one of the - dependent bases. */ - if (b_kind == bk_same_type || !any_dependent_bases_p ()) + base_kind b_kind; + tree binfo = lookup_base (current, scope, ba_any, &b_kind, + tf_warning_or_error); + if (b_kind < bk_proper_base) + { + /* If there are dependent bases, scope might resolve at + instantiation time, even if it isn't exactly one of + the dependent bases. */ + if (b_kind == bk_same_type || !any_dependent_bases_p ()) + { + error_not_base_type (scope, current); + return false; + } + /* Treat as-if dependent. */ + dependent_p = true; + } + else if (lookup.name == ctor_identifier && !binfo_direct_p (binfo)) { - error_not_base_type (scope, current_class_type); - return NULL_TREE; + error ("cannot inherit constructors from indirect base %qT", + scope); + return false; } + else if (IDENTIFIER_CONV_OP_P (lookup.name) + && dependent_type_p (TREE_TYPE (lookup.name))) + dependent_p = true; + else + lookup.value = lookup_member (binfo, lookup.name, 0, + false, tf_warning_or_error); } - else if (name == ctor_identifier && !binfo_direct_p (binfo)) + } + + if (!dependent_p) + { + if (!lookup.value) { - error ("cannot inherit constructors from indirect base %qT", scope); - return NULL_TREE; + error ("%qD has not been declared in %qE", lookup.name, scope); + return false; } - else if (!IDENTIFIER_CONV_OP_P (name) - || !dependent_type_p (TREE_TYPE (name))) + + if (TREE_CODE (lookup.value) == TREE_LIST + /* We can (independently) have ambiguous implicit typedefs. */ + || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST)) { - decl = lookup_member (binfo, name, 0, false, tf_warning_or_error); - if (!decl) - { - error ("no members matching %<%T::%D%> in %q#T", scope, name, - scope); - return NULL_TREE; - } + error ("reference to %qD is ambiguous", lookup.name); + print_candidates (TREE_CODE (lookup.value) == TREE_LIST + ? lookup.value : lookup.type); + return false; + } - /* The binfo from which the functions came does not matter. */ - if (BASELINK_P (decl)) - decl = BASELINK_FUNCTIONS (decl); + if (TREE_CODE (lookup.value) == NAMESPACE_DECL) + { + error ("using-declaration may not name namespace %qD", lookup.value); + return false; } } - tree value = build_lang_decl (USING_DECL, name, NULL_TREE); - USING_DECL_DECLS (value) = decl; - USING_DECL_SCOPE (value) = scope; - DECL_DEPENDENT_P (value) = !decl; + return true; +} + +/* Process "using SCOPE::NAME" in a class scope. Return the + USING_DECL created. */ + +tree +do_class_using_decl (tree scope, tree name) +{ + if (name == error_mark_node + || scope == error_mark_node) + return NULL_TREE; + + name_lookup lookup (name, 0); + if (!lookup_using_decl (scope, lookup)) + return NULL_TREE; + + tree found = lookup.value; + if (found && BASELINK_P (found)) + /* The binfo from which the functions came does not matter. */ + found = BASELINK_FUNCTIONS (found); + + tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE); + USING_DECL_SCOPE (using_decl) = scope; + USING_DECL_DECLS (using_decl) = found; + DECL_DEPENDENT_P (using_decl) = !found; - return value; + return using_decl; } @@ -5046,39 +5110,14 @@ void finish_nonmember_using_decl (tree scope, tree name) { gcc_checking_assert (current_binding_level->kind != sk_class); - gcc_checking_assert (identifier_p (name)); - name_lookup lookup (name, 0); - - if (TREE_CODE (scope) != NAMESPACE_DECL) - { - error ("%qE is not a namespace or unscoped enum", scope); - return; - } - - qualified_namespace_lookup (scope, &lookup); - - if (!lookup.value) - { - error ("%qD has not been declared in %qE", name, scope); - return; - } + if (scope == error_mark_node || name == error_mark_node) + return; - if (TREE_CODE (lookup.value) == TREE_LIST - /* But we can (independently) have ambiguous implicit typedefs. */ - || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST)) - { - error ("reference to %qD is ambiguous", name); - print_candidates (TREE_CODE (lookup.value) == TREE_LIST - ? lookup.value : lookup.type); - return; - } + name_lookup lookup (name, 0); - if (TREE_CODE (lookup.value) == NAMESPACE_DECL) - { - error ("using-declaration may not name namespace %qD", lookup.value); - return; - } + if (!lookup_using_decl (scope, lookup)) + return; /* Emit debug info. */ if (!processing_template_decl) @@ -5106,7 +5145,7 @@ finish_nonmember_using_decl (tree scope, tree name) } else { - tree using_decl = build_lang_decl (USING_DECL, name, NULL_TREE); + tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE); USING_DECL_SCOPE (using_decl) = scope; add_decl_expr (using_decl); @@ -5147,7 +5186,6 @@ finish_nonmember_using_decl (tree scope, tree name) set_identifier_type_value (name, type); } } - } /* Return the declarations that are members of the namespace NS. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 557209336ff..a03b6844d29 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2019-11-12 Nathan Sidwell + + * g++.dg/cpp0x/using-enum-2.C: Adjust expected error text. + * g++.dg/cpp0x/using-enum-3.C: Likewise. + * g++.dg/lookup/using4.C: Likewise. + * g++.dg/lookup/using7.C: Likewise. + * g++.dg/template/using12.C: Likewise. + * g++.dg/template/using18.C: Likewise. + * g++.dg/template/using22.C: Likewise. + 2019-11-12 Segher Boessenkool PR target/92449 diff --git a/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C b/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C index 0738c802b34..faa38179305 100644 --- a/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C +++ b/gcc/testsuite/g++.dg/cpp0x/using-enum-2.C @@ -5,16 +5,16 @@ namespace A { enum class E { V }; - using E::V; // { dg-error "not a namespace or unscoped enum" } + using E::V; // { dg-error "name enumerator" } } void foo() { - using A::E::V; // { dg-error "not a namespace or unscoped enum" } + using A::E::V; // { dg-error "name enumerator" } } -using A::E::V; // { dg-error "not a namespace or unscoped enum" } +using A::E::V; // { dg-error "name enumerator" } enum class F { U }; -using F::U; // { dg-error "not a namespace or unscoped enum" } +using F::U; // { dg-error "name enumerator" } diff --git a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C index edc16890cb1..ecc4ddcccd8 100644 --- a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C +++ b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C @@ -4,7 +4,7 @@ void f () { enum e { a }; - using e::a; // { dg-error "not a namespace or unscoped enum" } + using e::a; // { dg-error "name enumerator" } } struct S { diff --git a/gcc/testsuite/g++.dg/lookup/using4.C b/gcc/testsuite/g++.dg/lookup/using4.C index a6421c87598..facb2b4fd31 100644 --- a/gcc/testsuite/g++.dg/lookup/using4.C +++ b/gcc/testsuite/g++.dg/lookup/using4.C @@ -10,6 +10,6 @@ template struct Bar : public Foo { void foo() { - using Foo::i; // { dg-error "not a namespace" } + using Foo::i; // { dg-error "member at non-class scope" } } }; diff --git a/gcc/testsuite/g++.dg/lookup/using7.C b/gcc/testsuite/g++.dg/lookup/using7.C index f774021d9b4..d92bf23d71d 100644 --- a/gcc/testsuite/g++.dg/lookup/using7.C +++ b/gcc/testsuite/g++.dg/lookup/using7.C @@ -6,7 +6,6 @@ template struct A template struct B : A // { dg-error "incomplete" } { using A::i; // { dg-error "incomplete" "incomplete" } - // { dg-error "using" "using" { target *-*-* } .-1 } }; B b; // { dg-message "required" } diff --git a/gcc/testsuite/g++.dg/template/using12.C b/gcc/testsuite/g++.dg/template/using12.C index cebfab1ee0b..0b652350e2a 100644 --- a/gcc/testsuite/g++.dg/template/using12.C +++ b/gcc/testsuite/g++.dg/template/using12.C @@ -3,5 +3,5 @@ struct A { template struct S : public A { - using A::operator(); // { dg-error "no member" } + using A::operator(); // { dg-error "has not been declared" } }; diff --git a/gcc/testsuite/g++.dg/template/using18.C b/gcc/testsuite/g++.dg/template/using18.C index b4ef6df478c..caafdcfe140 100644 --- a/gcc/testsuite/g++.dg/template/using18.C +++ b/gcc/testsuite/g++.dg/template/using18.C @@ -25,7 +25,7 @@ template struct B2 {}; template struct C : B1, B2 { - using B1::x; // { dg-error "no member" } + using B1::x; // { dg-error "has not been declared" } using B2::y; using typename B2::type; }; diff --git a/gcc/testsuite/g++.dg/template/using22.C b/gcc/testsuite/g++.dg/template/using22.C index 9ea3d8a1e49..041b5c1348f 100644 --- a/gcc/testsuite/g++.dg/template/using22.C +++ b/gcc/testsuite/g++.dg/template/using22.C @@ -16,25 +16,25 @@ struct A template struct A::B : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } }; template struct A::C : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } }; template struct A::D : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } }; template struct A::E : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } }; template -- 2.30.2