From patchwork Thu May 25 18:54:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 767088 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 3wYdjP1Mp3z9s8J for ; Fri, 26 May 2017 04:54:31 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="RZZ3x8Yz"; dkim-atps=neutral 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=iLFKp0B9mhghP/UUoC+DfOKn+jJwKJ5Y/4lvMuOjy7iuX6hVWs sErDdIzuU+OeZrrWURaxyLEKX/UH/eLNWNj4XgRcjgSuE2XJgzDJl9IrqYlpiVX2 y5eE+mfFq4Vnh7KEmXskiZl3mJ3bRqrvOPuig/XTuzYW98cgt2e9oEFY0= 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=UAzLQmOo0Ev9hWhczc73cpSFDC0=; b=RZZ3x8YzAVtPQtrnmkO4 t2fueFvlVd07yv3A5ZMg7+QOqw9H6xYkOITLX05N+LuCDRDHfN0RCKzKTBrfo/QB cWZXD8sVXjG157zfdjBEyumEvD8UeKLpEETR6i4u6aXHd3Bdq0PLHDVWm39cwMdL xTCZtrTMJJHBgcg1/Gacuog= Received: (qmail 45546 invoked by alias); 25 May 2017 18:54:15 -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 45474 invoked by uid 89); 25 May 2017 18:54:12 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-16.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mail-yb0-f171.google.com Received: from mail-yb0-f171.google.com (HELO mail-yb0-f171.google.com) (209.85.213.171) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 25 May 2017 18:54:09 +0000 Received: by mail-yb0-f171.google.com with SMTP id 132so54696921ybq.1 for ; Thu, 25 May 2017 11:54:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:to:from:subject:message-id:date :user-agent:mime-version:content-language; bh=M4w6DUlZB7FJNtM2M3IERlP5Ygg3rHjKK8SkwEJe1qo=; b=Zo16h5MGwsUAaPjUtfZcPM//LqwrvHAohpe6JycATvUTdPHmsutrQpVmBV6TZTGYXs HZ7xRUVTUoukH2KNH639a/KzoD4ozDIuOp027muAwkoEfn2tXfvoNkRb7bxaJfKtyK+3 oHW7p7FHaYPwQAuu43qd+nyNsllRScPerSAu129RSGtrNRSLfLWEg/XsEAH6Q9/PPUdi t8yOSxUy1QtVVjdFJTTyS9OsHYjUVjxcjLVfIfRmN7FAakHj4Bq2bMVpbrxSjuNHqd/Y THADmvKAMhql+NVBNgbIoFpUpIiRd9l5d1PMTNxYmOWrjVP/mC5dNY0TtCJNJKZXqI4Z 6brw== X-Gm-Message-State: AODbwcC+J6Q/mEi1iyb31ftJ1cOc+aL3tRpDz+6wpWrHUV3nuvIJwooI fYAX1dGj8ckyhA== X-Received: by 10.37.220.145 with SMTP id y139mr16487524ybe.88.1495738451092; Thu, 25 May 2017 11:54:11 -0700 (PDT) Received: from ?IPv6:2620:10d:c0a3:20fb:f6d0:5ac5:64cd:f102? ([2620:10d:c091:200::2:a1d1]) by smtp.googlemail.com with ESMTPSA id u3sm3882690ywu.10.2017.05.25.11.54.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 May 2017 11:54:10 -0700 (PDT) To: GCC Patches From: Nathan Sidwell Subject: [C++ PATCH] Kill DECL_NAMESPACE_USERS, DECL_NAMESPACE_ASSOCIATIONS. Message-ID: <254b3614-f59e-3259-5b63-d05c043c4d6e@acm.org> Date: Thu, 25 May 2017 14:54:08 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.1.0 MIME-Version: 1.0 With namespace lookup reimplemented we need neither DECL_NAMESPACE_USERS nor DECL_NAMESPACE_ASSOCIATIONS. This patch nukes them. The change in libcp1plugin.cc, which checks before setting will make more sense when the next change to inline namespace representation lands. nathan 2017-05-25 Nathan Sidwell gcc/cp/ Kill DECL_NAMESPACE_USERS, DECL_NAMESPACE_ASSOCIATIONS. * cp-tree.h (lang_decl_ns): Remove ns_users field. (DECL_NAMESPACE_USERS, DECL_NAMESPACE_ASSOCIATIONS): Delete. (TREE_INDIRECT_USING): Delete. * name-lookup.h (is_associated_namespace): Delete. * name-lookup.c (name_lookup::search_usings, name_lookup::do_queue_usings): Usings are always direct. (is_associated_namespace): Delete. (handle_namespace_attrs): Use DECL_NAMESPACE_INLINE_P. (namespace_ancestor_1, namespace_ancestor): Delete. (push_using_directive_1, push_using_directive): Delete. (add_using_namespace_1): Delete. (add_using_namespace): Reimplement. (emit_debug_info_using_namespace): New. (finish_namespace_using_directive, finish_local_using_directive, push_namespace): Adjust. * tree.c (cp_free_lang_data): Remove DECL_NAMESPACE_USERS handling. libcc1/ * libcp1plugin.cc (plugin_make_namespace_inline): Check and set DECL_NAMESPACE_INLINE_P. gcc/testsuite/ * g++.dg/lookup/using56.C: New. * g++.dg/lookup/using57.C: New. * g++.dg/lookup/using58.C: New. * g++.dg/lookup/using59.C: New. Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 248457) +++ gcc/cp/cp-tree.h (working copy) @@ -328,7 +328,6 @@ extern GTY(()) tree cp_global_trees[CPTI BASELINK_QUALIFIED_P (in BASELINK) TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR) TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX) - TREE_INDIRECT_USING (in a TREE_LIST of using-directives) ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute) ABI_TAG_IMPLICIT (in the TREE_LIST for the argument of abi_tag) CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR) @@ -2513,7 +2512,6 @@ struct GTY(()) lang_decl_ns { struct lang_decl_base base; cp_binding_level *level; tree ns_using; - tree ns_users; }; /* DECL_LANG_SPECIFIC for parameters. */ @@ -3085,15 +3083,6 @@ struct GTY(()) lang_decl { that is the common ancestor. */ #define DECL_NAMESPACE_USING(NODE) (LANG_DECL_NS_CHECK (NODE)->ns_using) -/* In a NAMESPACE_DECL, the DECL_INITIAL is used to record all users - of a namespace, to record the transitive closure of using namespace. */ -#define DECL_NAMESPACE_USERS(NODE) (LANG_DECL_NS_CHECK (NODE)->ns_users) - -/* In a NAMESPACE_DECL, the list of namespaces which have associated - themselves with this one. */ -#define DECL_NAMESPACE_ASSOCIATIONS(NODE) \ - DECL_INITIAL (NAMESPACE_DECL_CHECK (NODE)) - /* In a NAMESPACE_DECL, points to the original namespace if this is a namespace alias. */ #define DECL_NAMESPACE_ALIAS(NODE) \ @@ -3107,10 +3096,6 @@ struct GTY(()) lang_decl { && CP_DECL_CONTEXT (NODE) == global_namespace \ && DECL_NAME (NODE) == std_identifier) -/* In a TREE_LIST concatenating using directives, indicate indirect - directives */ -#define TREE_INDIRECT_USING(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE)) - /* In a TREE_LIST in an attribute list, indicates that the attribute must be applied at instantiation time. */ #define ATTR_IS_DEPENDENT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE)) Index: gcc/cp/name-lookup.c =================================================================== --- gcc/cp/name-lookup.c (revision 248465) +++ gcc/cp/name-lookup.c (working copy) @@ -533,8 +533,7 @@ name_lookup::search_usings (tree scope) /* Look in direct usings. */ for (tree usings = DECL_NAMESPACE_USING (scope); usings; usings = TREE_CHAIN (usings)) - if (!TREE_INDIRECT_USING (usings)) - found |= search_qualified (TREE_PURPOSE (usings), true); + found |= search_qualified (TREE_PURPOSE (usings), true); /* Look in its inline children. */ for (tree inner = NAMESPACE_LEVEL (scope)->namespaces; @@ -607,8 +606,7 @@ name_lookup::using_queue * name_lookup::do_queue_usings (using_queue *queue, int depth, tree usings) { for (; usings; usings = TREE_CHAIN (usings)) - if (!TREE_INDIRECT_USING (usings)) - queue = queue_namespace (queue, depth, TREE_PURPOSE (usings)); + queue = queue_namespace (queue, depth, TREE_PURPOSE (usings)); return queue; } @@ -1019,7 +1017,6 @@ static void consider_binding_level (tree cp_binding_level *lvl, bool look_within_fields, enum lookup_name_fuzzy_kind kind); -static tree push_using_directive (tree); static void diagnose_name_conflict (tree, tree); /* ADL lookup of NAME. FNS is the result of regular lookup, and we @@ -1036,47 +1033,6 @@ lookup_arg_dependent (tree name, tree fn return fns; } -/* Returns true iff CURRENT has declared itself to be an associated - namespace of SCOPE via a strong using-directive (or transitive chain - thereof). Both are namespaces. */ - -bool -is_associated_namespace (tree current, tree scope) -{ - vec *seen = make_tree_vector (); - vec *todo = make_tree_vector (); - tree t; - bool ret; - - while (1) - { - if (scope == current) - { - ret = true; - break; - } - vec_safe_push (seen, scope); - for (t = DECL_NAMESPACE_ASSOCIATIONS (scope); t; t = TREE_CHAIN (t)) - if (!vec_member (TREE_PURPOSE (t), seen)) - vec_safe_push (todo, TREE_PURPOSE (t)); - if (!todo->is_empty ()) - { - scope = todo->last (); - todo->pop (); - } - else - { - ret = false; - break; - } - } - - release_tree_vector (seen); - release_tree_vector (todo); - - return ret; -} - /* Compute the chain index of a binding_entry given the HASH value of its name and the total COUNT of chains. COUNT is assumed to be a power of 2. */ @@ -4426,15 +4382,15 @@ handle_namespace_attrs (tree ns, tree at } else if (is_attribute_p ("abi_tag", name)) { - if (!DECL_NAMESPACE_ASSOCIATIONS (ns)) + if (!DECL_NAME (ns)) { - warning (OPT_Wattributes, "ignoring %qD attribute on non-inline " + warning (OPT_Wattributes, "ignoring %qD attribute on anonymous " "namespace", name); continue; } - if (!DECL_NAME (ns)) + if (!DECL_NAMESPACE_INLINE_P (ns)) { - warning (OPT_Wattributes, "ignoring %qD attribute on anonymous " + warning (OPT_Wattributes, "ignoring %qD attribute on non-inline " "namespace", name); continue; } @@ -4479,32 +4435,6 @@ pop_decl_namespace (void) decl_namespace_list->pop (); } -/* Return the namespace that is the common ancestor - of two given namespaces. */ - -static tree -namespace_ancestor_1 (tree ns1, tree ns2) -{ - tree nsr; - if (is_ancestor (ns1, ns2)) - nsr = ns1; - else - nsr = namespace_ancestor_1 (CP_DECL_CONTEXT (ns1), ns2); - return nsr; -} - -/* Wrapper for namespace_ancestor_1. */ - -static tree -namespace_ancestor (tree ns1, tree ns2) -{ - tree nsr; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - nsr = namespace_ancestor_1 (ns1, ns2); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return nsr; -} - /* Process a namespace-alias declaration. */ void @@ -5537,44 +5467,6 @@ is_local_extern (tree decl) return false; } -/* Add namespace to using_directives. Return NULL_TREE if nothing was - changed (i.e. there was already a directive), or the fresh - TREE_LIST otherwise. */ - -static tree -push_using_directive_1 (tree used) -{ - tree ud = current_binding_level->using_directives; - tree iter, ancestor; - - /* Check if we already have this. */ - if (purpose_member (used, ud) != NULL_TREE) - return NULL_TREE; - - ancestor = namespace_ancestor (current_decl_namespace (), used); - ud = current_binding_level->using_directives; - ud = tree_cons (used, ancestor, ud); - current_binding_level->using_directives = ud; - - /* Recursively add all namespaces used. */ - for (iter = DECL_NAMESPACE_USING (used); iter; iter = TREE_CHAIN (iter)) - push_using_directive_1 (TREE_PURPOSE (iter)); - - return ud; -} - -/* Wrapper for push_using_directive_1. */ - -static tree -push_using_directive (tree used) -{ - tree ret; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = push_using_directive_1 (used); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - /* The type TYPE is being declared. If it is a class template, or a specialization of a class template, do any processing required and perform error-checking. If IS_FRIEND is nonzero, this TYPE is @@ -6094,64 +5986,29 @@ do_pop_nested_namespace (tree ns) do_pop_from_top_level (); } -/* Insert USED into the using list of USER. Set INDIRECT_flag if this - directive is not directly from the source. Also find the common - ancestor and let our users know about the new namespace */ +/* Add TARGET to USINGS, if it does not already exist there. + We used to build the complete graph of usings at this point, from + the POV of the source namespaces. Now we build that as we perform + the unqualified search. */ static void -add_using_namespace_1 (tree user, tree used, bool indirect) +add_using_namespace (tree &usings, tree target) { - tree t; - /* Using oneself is a no-op. */ - if (user == used) - return; - gcc_assert (TREE_CODE (user) == NAMESPACE_DECL); - gcc_assert (TREE_CODE (used) == NAMESPACE_DECL); - /* Check if we already have this. */ - t = purpose_member (used, DECL_NAMESPACE_USING (user)); - if (t != NULL_TREE) - { - if (!indirect) - /* Promote to direct usage. */ - TREE_INDIRECT_USING (t) = 0; + for (tree probe = usings; probe; probe = TREE_CHAIN (probe)) + if (target == TREE_PURPOSE (probe)) return; - } - - /* Add used to the user's using list. */ - DECL_NAMESPACE_USING (user) - = tree_cons (used, namespace_ancestor (user, used), - DECL_NAMESPACE_USING (user)); - - TREE_INDIRECT_USING (DECL_NAMESPACE_USING (user)) = indirect; - /* Add user to the used's users list. */ - DECL_NAMESPACE_USERS (used) - = tree_cons (user, 0, DECL_NAMESPACE_USERS (used)); - - /* Recursively add all namespaces used. */ - for (t = DECL_NAMESPACE_USING (used); t; t = TREE_CHAIN (t)) - /* indirect usage */ - add_using_namespace_1 (user, TREE_PURPOSE (t), 1); - - /* Tell everyone using us about the new used namespaces. */ - for (t = DECL_NAMESPACE_USERS (user); t; t = TREE_CHAIN (t)) - add_using_namespace_1 (TREE_PURPOSE (t), used, 1); + usings = tree_cons (target, NULL_TREE, usings); } -/* Wrapper for add_using_namespace_1. */ +/* Tell the debug system of a using directive. */ static void -add_using_namespace (bool namespace_level_p, tree from, tree target) +emit_debug_info_using_namespace (tree from, tree target) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - add_using_namespace_1 (from, target, false); - if (namespace_level_p) - { - /* Emit debugging info. */ - tree context = from != global_namespace ? from : NULL_TREE; - debug_hooks->imported_module_or_decl (target, NULL_TREE, context, false); - } - timevar_cond_stop (TV_NAME_LOOKUP, subtime); + /* Emit debugging info. */ + tree context = from != global_namespace ? from : NULL_TREE; + debug_hooks->imported_module_or_decl (target, NULL_TREE, context, false); } /* Process a namespace-scope using directive. */ @@ -6163,8 +6020,10 @@ finish_namespace_using_directive (tree t if (target == error_mark_node) return; - add_using_namespace (true, current_namespace, + add_using_namespace (DECL_NAMESPACE_USING (current_namespace), ORIGINAL_NAMESPACE (target)); + emit_debug_info_using_namespace (current_namespace, + ORIGINAL_NAMESPACE (target)); if (attribs == error_mark_node) return; @@ -6198,7 +6057,8 @@ finish_local_using_directive (tree targe add_stmt (build_stmt (input_location, USING_STMT, target)); - push_using_directive (ORIGINAL_NAMESPACE (target)); + add_using_namespace (current_binding_level->using_directives, + ORIGINAL_NAMESPACE (target)); } /* Pushes X into the global namespace. */ @@ -6306,20 +6166,14 @@ push_namespace (tree name, bool make_inl DECL_NAME (ns) = NULL_TREE; if (!make_inline) - add_using_namespace (true, current_namespace, ns); + add_using_namespace (DECL_NAMESPACE_USING (current_namespace), + ns); } else if (TREE_PUBLIC (current_namespace)) TREE_PUBLIC (ns) = 1; if (make_inline) - { - DECL_NAMESPACE_INLINE_P (ns) = true; - /* Set up namespace association. */ - DECL_NAMESPACE_ASSOCIATIONS (ns) - = tree_cons (current_namespace, NULL_TREE, NULL_TREE); - /* Import the contents of the inline namespace. */ - add_using_namespace (true, current_namespace, ns); - } + DECL_NAMESPACE_INLINE_P (ns) = true; } } Index: gcc/cp/name-lookup.h =================================================================== --- gcc/cp/name-lookup.h (revision 248457) +++ gcc/cp/name-lookup.h (working copy) @@ -325,7 +325,6 @@ extern void do_namespace_alias (tree, tr extern tree do_class_using_decl (tree, tree); extern void do_using_directive (tree); extern tree lookup_arg_dependent (tree, tree, vec *); -extern bool is_associated_namespace (tree, tree); extern tree innermost_non_namespace_value (tree); extern cxx_binding *outer_binding (tree, cxx_binding *, bool); extern void cp_emit_debug_info_for_using (tree, tree); Index: gcc/cp/tree.c =================================================================== --- gcc/cp/tree.c (revision 248452) +++ gcc/cp/tree.c (working copy) @@ -5123,14 +5123,9 @@ cp_free_lang_data (tree t) TREE_STATIC (t) = 0; } if (TREE_CODE (t) == NAMESPACE_DECL) - { - /* The list of users of a namespace isn't useful for the middle-end - or debug generators. */ - DECL_NAMESPACE_USERS (t) = NULL_TREE; - /* Neither do we need the leftover chaining of namespaces - from the binding level. */ - DECL_CHAIN (t) = NULL_TREE; - } + /* We do not need the leftover chaining of namespaces from the + binding level. */ + DECL_CHAIN (t) = NULL_TREE; } /* Stub for c-common. Please keep in sync with c-decl.c. Index: libcc1/libcp1plugin.cc =================================================================== --- libcc1/libcp1plugin.cc (revision 248452) +++ libcc1/libcp1plugin.cc (working copy) @@ -930,20 +930,10 @@ plugin_make_namespace_inline (cc1_plugin tree parent_ns = CP_DECL_CONTEXT (inline_ns); - if (purpose_member (DECL_NAMESPACE_ASSOCIATIONS (inline_ns), - parent_ns)) + if (DECL_NAMESPACE_INLINE_P (inline_ns)) return 0; - pop_namespace (); - - gcc_assert (current_namespace == parent_ns); - - DECL_NAMESPACE_ASSOCIATIONS (inline_ns) - = tree_cons (parent_ns, 0, - DECL_NAMESPACE_ASSOCIATIONS (inline_ns)); - do_using_directive (inline_ns); - - push_namespace (DECL_NAME (inline_ns)); + DECL_NAMESPACE_INLINE_P (inline_ns) = true; return 1; } Index: gcc/testsuite/g++.dg/lookup/using56.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using56.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using56.C (working copy) @@ -0,0 +1,16 @@ + +// The anticipated decl for 'log' got retained, leading to confusion */ + +extern double log (double) throw (); + +namespace std +{ + using ::log; + float log (float) throw (); + long double log (long double) throw (); +} + +void Foo (double x) +{ + std::log (x); +} Index: gcc/testsuite/g++.dg/lookup/using57.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using57.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using57.C (working copy) @@ -0,0 +1,29 @@ +// Addr of function from multiple namespaces + +namespace X +{ + void Foo (int); + void Foo (short); +} + +namespace Y +{ + void Foo (float); + void Foo (double); +} + +template void Foo (T *); + +using namespace X; + +using namespace Y; + +void (*(Baz ())) (float) +{ + return Foo; +} + +void (*(Bar ())) (void *) +{ + return Foo; +} Index: gcc/testsuite/g++.dg/lookup/using58.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using58.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using58.C (working copy) @@ -0,0 +1,18 @@ + + +void Foo (int); +void Foo (double); + +namespace Y +{ + void Baz (int); // { dg-message "previous declaration" } +} + +void X () +{ + using ::Foo; + extern void Foo (int); + + using Y::Baz; + extern void Baz (int); // { dg-error "conflicts with" } +} Index: gcc/testsuite/g++.dg/lookup/using59.C =================================================================== --- gcc/testsuite/g++.dg/lookup/using59.C (revision 0) +++ gcc/testsuite/g++.dg/lookup/using59.C (working copy) @@ -0,0 +1,12 @@ + +namespace Y +{ + extern int I; // { dg-message "previous declaration" } +} + +using Y::I; +extern int I; // { dg-error "conflicts with a previous" } + +extern int J; +extern int J; // { dg-message "previous declaration" } +extern char J; // { dg-error "conflicting declaration" }