From ef4c5e7855ea00a62487c0d34915d66946032172 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Wed, 24 May 2017 11:28:54 +0000 Subject: [PATCH] cp-tree.h (OVL_HIDDEN_P): New. gcc/cp/ * cp-tree.h (OVL_HIDDEN_P): New. (ovl_iterator::hidden_p, ovl_iterator::reveal_node): New. (ovl_iterator::reveal_node): Declare. * tree.c (ovl_copy): Copy OVL_HIDDEN_P. (ovl_insert): Order on hiddenness. (ovl_iterator::reveal_node): New. * name-lookup.c (anticipated_builtin_p): New. (supplement_binding_1): Use it. (set_local_extern_decl_linkage): Use hidden_p. (do_pushdecl): Deal with unhiding a hidden decl, use anticipated_builtin_p. (do_nonmember_using_decl): Use anticipated_decl_p. (lookup_name_real_1): Use DECL_HIDDEN_P. gcc/testsuite/ * g++.dg/lookup/extern-c-hidden.C: New. * g++.dg/lookup/extern-redecl1.C: New. From-SVN: r248406 --- gcc/cp/ChangeLog | 16 +++++ gcc/cp/cp-tree.h | 16 ++++- gcc/cp/name-lookup.c | 66 ++++++++++++++----- gcc/cp/tree.c | 35 ++++++++-- gcc/testsuite/ChangeLog | 3 + gcc/testsuite/g++.dg/lookup/extern-c-hidden.C | 11 ++++ gcc/testsuite/g++.dg/lookup/extern-redecl1.C | 18 +++++ 7 files changed, 144 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-hidden.C create mode 100644 gcc/testsuite/g++.dg/lookup/extern-redecl1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 785dfc56fc0..16e30fa43d7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2017-05-24 Nathan Sidwell + + * cp-tree.h (OVL_HIDDEN_P): New. + (ovl_iterator::hidden_p, ovl_iterator::reveal_node): New. + (ovl_iterator::reveal_node): Declare. + * tree.c (ovl_copy): Copy OVL_HIDDEN_P. + (ovl_insert): Order on hiddenness. + (ovl_iterator::reveal_node): New. + * name-lookup.c (anticipated_builtin_p): New. + (supplement_binding_1): Use it. + (set_local_extern_decl_linkage): Use hidden_p. + (do_pushdecl): Deal with unhiding a hidden decl, use + anticipated_builtin_p. + (do_nonmember_using_decl): Use anticipated_decl_p. + (lookup_name_real_1): Use DECL_HIDDEN_P. + 2017-05-23 Jason Merrill -Wunused and C++17 structured bindings diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2ed9e5aa473..7f1c632da1d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -378,6 +378,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF) AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) + OVL_HIDDEN_P (in OVERLOAD) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -659,6 +660,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t; /* If set, this was imported in a using declaration. */ #define OVL_USING_P(NODE) TREE_LANG_FLAG_1 (OVERLOAD_CHECK (NODE)) +/* If set, this overload is a hidden decl. */ +#define OVL_HIDDEN_P(NODE) TREE_LANG_FLAG_2 (OVERLOAD_CHECK (NODE)) /* If set, this overload contains a nested overload. */ #define OVL_NESTED_P(NODE) TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE)) /* If set, this overload was constructed during lookup. */ @@ -729,15 +732,26 @@ class ovl_iterator { return TREE_CODE (ovl) == OVERLOAD && OVL_USING_P (ovl); } + bool hidden_p () const + { + return TREE_CODE (ovl) == OVERLOAD && OVL_HIDDEN_P (ovl); + } + + public: tree remove_node (tree head) { return remove_node (head, ovl); } + tree reveal_node (tree head) + { + return reveal_node (head, ovl); + } private: - /* We make this a static function to avoid the address of the + /* We make these static functions to avoid the address of the iterator escaping the local context. */ static tree remove_node (tree head, tree node); + static tree reveal_node (tree ovl, tree node); }; /* Iterator over a (potentially) 2 dimensional overload, which is diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 89d4e2ad1db..57d85a5a017 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1077,6 +1077,26 @@ strip_using_decl (tree decl) return decl; } +/* Return true if OVL is an overload for an anticipated builtin. */ + +static bool +anticipated_builtin_p (tree ovl) +{ + if (TREE_CODE (ovl) != OVERLOAD) + return false; + + if (!OVL_HIDDEN_P (ovl)) + return false; + + tree fn = OVL_FUNCTION (ovl); + gcc_checking_assert (DECL_ANTICIPATED (fn)); + + if (DECL_HIDDEN_FRIEND_P (fn)) + return false; + + return true; +} + /* BINDING records an existing declaration for a name in the current scope. But, DECL is another declaration for that same identifier in the same scope. This is the `struct stat' hack whereby a non-typedef @@ -1131,9 +1151,7 @@ supplement_binding_1 (cxx_binding *binding, tree decl) || target_bval == error_mark_node /* If TARGET_BVAL is anticipated but has not yet been declared, pretend it is not there at all. */ - || (TREE_CODE (target_bval) == FUNCTION_DECL - && DECL_ANTICIPATED (target_bval) - && !DECL_HIDDEN_FRIEND_P (target_bval))) + || anticipated_builtin_p (target_bval)) binding->value = decl; else if (TREE_CODE (target_bval) == TYPE_DECL && DECL_ARTIFICIAL (target_bval) @@ -1803,7 +1821,7 @@ set_local_extern_decl_linkage (tree decl, bool shadowed) loc_value = NULL_TREE; for (ovl_iterator iter (loc_value); iter; ++iter) - if (!DECL_HIDDEN_P (*iter) + if (!iter.hidden_p () && (TREE_STATIC (*iter) || DECL_EXTERNAL (*iter)) && decls_match (*iter, decl)) { @@ -1931,15 +1949,34 @@ do_pushdecl (tree decl, bool is_friend) if (iter.using_p ()) ; /* Ignore using decls here. */ else if (tree match = duplicate_decls (decl, *iter, is_friend)) - return match; + { + if (iter.hidden_p () + && match != error_mark_node + && !DECL_HIDDEN_P (match)) + { + /* Unhiding a previously hidden decl. */ + tree head = iter.reveal_node (old); + if (head != old) + { + if (!ns) + update_local_overload (binding, head); + binding->value = head; + } + + if (TREE_CODE (match) == FUNCTION_DECL + && DECL_EXTERN_C_P (match)) + /* We need to check and register the fn now. */ + check_extern_c_conflict (match); + } + return match; + } /* We are pushing a new decl. */ - /* Skip a hidden builtin we failed to match already. */ - if (old && TREE_CODE (old) == FUNCTION_DECL - && DECL_ANTICIPATED (old) - && !DECL_HIDDEN_FRIEND_P (old)) - old = NULL_TREE; + /* Skip a hidden builtin we failed to match already. There can + only be one. */ + if (old && anticipated_builtin_p (old)) + old = OVL_CHAIN (old); check_template_shadow (decl); @@ -3045,8 +3082,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p) found = true; else if (old.using_p ()) continue; /* This is a using decl. */ - else if (DECL_ANTICIPATED (old_fn) - && !DECL_HIDDEN_FRIEND_P (old_fn)) + else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn)) continue; /* This is an anticipated builtin. */ else if (!matching_fn_p (new_fn, old_fn)) continue; /* Parameters do not match. */ @@ -3069,9 +3105,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p) } else if (value /* Ignore anticipated builtins. */ - && !(TREE_CODE (value) == FUNCTION_DECL - && DECL_ANTICIPATED (value) - && !DECL_HIDDEN_FRIEND_P (value)) + && !anticipated_builtin_p (value) && !decls_match (lookup.value, value)) diagnose_name_conflict (lookup.value, value); else @@ -5244,7 +5278,7 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p, if (binding) { - if (hidden_name_p (binding)) + if (TREE_CODE (binding) == TYPE_DECL && DECL_HIDDEN_P (binding)) { /* A non namespace-scope binding can only be hidden in the presence of a local class, due to friend declarations. diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8490c817f81..5ae9601aaef 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2143,7 +2143,8 @@ ovl_copy (tree ovl) TREE_TYPE (result) = TREE_TYPE (ovl); OVL_FUNCTION (result) = OVL_FUNCTION (ovl); OVL_CHAIN (result) = OVL_CHAIN (ovl); - OVL_USING_P (ovl) = OVL_USING_P (ovl); + OVL_HIDDEN_P (result) = OVL_HIDDEN_P (ovl); + OVL_USING_P (result) = OVL_USING_P (ovl); return result; } @@ -2156,14 +2157,16 @@ tree ovl_insert (tree fn, tree maybe_ovl, bool using_p) { bool copying = false; /* Checking use only. */ - int weight = using_p; + bool hidden_p = DECL_HIDDEN_P (fn); + int weight = (hidden_p << 1) | (using_p << 0); tree result = NULL_TREE; tree insert_after = NULL_TREE; /* Find insertion point. */ while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD - && (weight < OVL_USING_P (maybe_ovl))) + && (weight < ((OVL_HIDDEN_P (maybe_ovl) << 1) + | (OVL_USING_P (maybe_ovl) << 0)))) { gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl) && (!OVL_USED_P (maybe_ovl) || !copying)); @@ -2181,9 +2184,11 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) } tree trail = fn; - if (maybe_ovl || using_p || TREE_CODE (fn) == TEMPLATE_DECL) + if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL) { trail = ovl_make (fn, maybe_ovl); + if (hidden_p) + OVL_HIDDEN_P (trail) = true; if (using_p) OVL_USING_P (trail) = true; } @@ -2199,6 +2204,28 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) return result; } +/* NODE is an OVL_HIDDEN_P node which is now revealed. */ + +tree +ovl_iterator::reveal_node (tree overload, tree node) +{ + /* We cannot have returned NODE as part of a lookup overload, so it + cannot be USED. */ + gcc_checking_assert (!OVL_USED_P (node)); + + OVL_HIDDEN_P (node) = false; + if (tree chain = OVL_CHAIN (node)) + if (TREE_CODE (chain) == OVERLOAD + && (OVL_USING_P (chain) || OVL_HIDDEN_P (chain))) + { + /* The node needs moving, and the simplest way is to remove it + and reinsert. */ + overload = remove_node (overload, node); + overload = ovl_insert (OVL_FUNCTION (node), overload); + } + return overload; +} + /* NODE is on the overloads of OVL. Remove it. If a predecessor is OVL_USED_P we must copy OVL nodes, because those are immutable. The removed node is unaltered and may continue to be iterated diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f536dda0fda..d8d16eebb8b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2017-05-23 Nathan Sidwell + * g++.dg/lookup/extern-c-hidden.C: New. + * g++.dg/lookup/extern-redecl1.C: New. + PR c++/80866 * g++.dg/parse/pr80866.C: New. diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C b/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C new file mode 100644 index 00000000000..a03dea02376 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C @@ -0,0 +1,11 @@ +// Make sure unhidding an extern-c still checks it is compatible + +extern "C" float fabsf (float); // { dg-error "conflicts with previous declaration" } + +namespace Bob +{ + extern "C" float fabsf (float, float); // { dg-error "C language" } + extern "C" double fabs (double, double); // { dg-error "conflicts with previous declaration" } +} + +extern "C" double fabs (double); // { dg-error "C language" } diff --git a/gcc/testsuite/g++.dg/lookup/extern-redecl1.C b/gcc/testsuite/g++.dg/lookup/extern-redecl1.C new file mode 100644 index 00000000000..18e675b4f3d --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/extern-redecl1.C @@ -0,0 +1,18 @@ +extern int X; // { dg-message "previous declaration" } +extern int Y (int); // { dg-message "previous declaration" } +extern int Y (float); + +static int Z (int s) +{ + return s; +} + +void Foo () +{ + extern char X; // { dg-error "local external declaration" } + extern char Y (int); // { dg-error "local external declaration" } + extern int Y (float); + extern void Y (double); + extern char Z (int); +} + -- 2.30.2