From patchwork Tue Nov 12 21:20:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 1193859 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-513179-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="vfgSWo8X"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="X5m2BOk0"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47CLJB005gz9s7T for ; Wed, 13 Nov 2019 08:20:41 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=x61HfuC35lbBCRPvJWtHhziKpR0DqOXfKCU3R5YAS52TAIBkGU OXNxLz8LEJ/WXJylu2FsRUV/vBWNqqQm45r0vsZ3O43PhU4F6xqGpFLXWHmkryYc KNw3aP7SlDRv+F+lL008nb/EAkBXY6qFkaybopqUiLIAusB5ntCezBmS4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; s= default; bh=zXGWQqMUdEiXS3H5UC4uVR0rtGA=; b=vfgSWo8XebKT3cooK4NB /LU/NGfxv57IcltA/7jcRkz7bbNMWqIqIgKnwQuO/yKbBRyFn3pUU7FkdWZ7SZLu V61MmdAHRIlXlM5NM7QcksxDU2+JnzdHqX4kwzmGusKfy40JJiP0uAJrxoHxtwAg RcYlras+fv4wJNNoQNhrYqA= Received: (qmail 93583 invoked by alias); 12 Nov 2019 21:20:33 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 93566 invoked by uid 89); 12 Nov 2019 21:20:32 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=tre, 11, 5 X-HELO: mail-qk1-f176.google.com Received: from mail-qk1-f176.google.com (HELO mail-qk1-f176.google.com) (209.85.222.176) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 12 Nov 2019 21:20:29 +0000 Received: by mail-qk1-f176.google.com with SMTP id i19so15881094qki.2 for ; Tue, 12 Nov 2019 13:20:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:to:from:subject:message-id:date:user-agent:mime-version :content-language; bh=vhERUd1ymxF9oW5+/dDM7GuWOsBNFzccQp5aalgkKGU=; b=X5m2BOk0FcCrJHGc3inF2dbMHQpvGSArto5R7dbK7RIA+9LlzQemfuXM+muqrQWuKW zcrB4QyKevVJREqJHMggjS2CJsiMx1jE4qL260pI6v6I4JDI2YAnkyAjp89/GJARfhrM +JyBoOLIw1GcdImPYEMfkeWn3R7jxUeRGgyhSJunFaKn9wdZAPmAWfyE+7jJNvNFCSbP wKdAh775w1kgaeT0HIS77jRmzoxV3JKp3Dr2H3RdJSjCnmgpXuFgZ4X8sr934AF3hJGG RH4X+PzRNTxVQ+lBsLjpeX0y/IjbWDtjEAKHrbX9kn2ZGLDv1pKtmvgsP9M1i2lLzgKo TnUQ== Received: from ?IPv6:2620:10d:c0a3:1407:a500:f6f8:6172:7eff? ([2620:10d:c091:500::3:2f0c]) by smtp.googlemail.com with ESMTPSA id i75sm10030615qke.22.2019.11.12.13.20.25 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 12 Nov 2019 13:20:26 -0800 (PST) To: GCC Patches From: Nathan Sidwell Subject: [C++ PATCH] Merge some using-decl handling Message-ID: Date: Tue, 12 Nov 2019 16:20:24 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.1.1 MIME-Version: 1.0 We currently process member and nonmember using decls completely separately. C++20 will have some new using decls for enums (see wg21.link/p1099 for details), and there will be some commonality -- member using decls can refer to non-member enumerators and non-member using-decls can refer to member enumerators. It makes sense to handle the lookup of using decls in one place, rather than duplicate the handling. This patch does that, with no change to semantics. Some error messages change, that is all. nathan 2019-11-12 Nathan Sidwell 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. Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 278096) +++ gcc/cp/name-lookup.c (working copy) @@ -4585,100 +4585,164 @@ push_class_level_binding (tree name, tre } -/* 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; + } + + /* 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; + } - /* From [namespace.udecl]: + /* 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; + } - A using-declaration used as a member-declaration shall refer to a - member of a base class of the class being defined. + /* 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) { - error_not_base_type (scope, current_class_type); - return NULL_TREE; + /* 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 ("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; +} - return value; +/* 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 using_decl; } @@ -5047,37 +5111,12 @@ finish_nonmember_using_decl (tree scope, { 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. */ @@ -5107,5 +5146,5 @@ finish_nonmember_using_decl (tree scope, 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); @@ -5148,5 +5187,4 @@ finish_nonmember_using_decl (tree scope, } } - } Index: gcc/testsuite/g++.dg/cpp0x/using-enum-2.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/using-enum-2.C (revision 278096) +++ gcc/testsuite/g++.dg/cpp0x/using-enum-2.C (working copy) @@ -6,15 +6,15 @@ 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" } Index: gcc/testsuite/g++.dg/cpp0x/using-enum-3.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/using-enum-3.C (revision 278096) +++ gcc/testsuite/g++.dg/cpp0x/using-enum-3.C (working copy) @@ -5,5 +5,5 @@ void f () { enum e { a }; - using e::a; // { dg-error "not a namespace or unscoped enum" } + using e::a; // { dg-error "name enumerator" } } Index: gcc/testsuite/g++.dg/lookup/using4.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using4.C (revision 278096) +++ gcc/testsuite/g++.dg/lookup/using4.C (working copy) @@ -11,5 +11,5 @@ struct Bar : public Foo { void foo() { - using Foo::i; // { dg-error "not a namespace" } + using Foo::i; // { dg-error "member at non-class scope" } } }; Index: gcc/testsuite/g++.dg/lookup/using7.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using7.C (revision 278096) +++ gcc/testsuite/g++.dg/lookup/using7.C (working copy) @@ -7,5 +7,4 @@ template struct B : A // { using A::i; // { dg-error "incomplete" "incomplete" } - // { dg-error "using" "using" { target *-*-* } .-1 } }; Index: gcc/testsuite/g++.dg/template/using12.C =================================================================== --- gcc/testsuite/g++.dg/template/using12.C (revision 278096) +++ gcc/testsuite/g++.dg/template/using12.C (working copy) @@ -4,4 +4,4 @@ struct A { template struct S : public A { - using A::operator(); // { dg-error "no member" } + using A::operator(); // { dg-error "has not been declared" } }; Index: gcc/testsuite/g++.dg/template/using18.C =================================================================== --- gcc/testsuite/g++.dg/template/using18.C (revision 278096) +++ gcc/testsuite/g++.dg/template/using18.C (working copy) @@ -26,5 +26,5 @@ 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; Index: gcc/testsuite/g++.dg/template/using22.C =================================================================== --- gcc/testsuite/g++.dg/template/using22.C (revision 278096) +++ gcc/testsuite/g++.dg/template/using22.C (working copy) @@ -17,5 +17,5 @@ template struct A::B : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } }; @@ -23,5 +23,5 @@ template struct A::C : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } }; @@ -29,5 +29,5 @@ template struct A::D : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } }; @@ -35,5 +35,5 @@ template struct A::E : A { - using A::nonexist; // { dg-error "no members matching" } + using A::nonexist; // { dg-error "has not been declared" } };