Commit ef4c5e78 by Nathan Sidwell Committed by Nathan Sidwell

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
parent b7fc9ae0
2017-05-24 Nathan Sidwell <nathan@acm.org>
* 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 <jason@redhat.com> 2017-05-23 Jason Merrill <jason@redhat.com>
-Wunused and C++17 structured bindings -Wunused and C++17 structured bindings
......
...@@ -378,6 +378,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; ...@@ -378,6 +378,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF) REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF)
AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR)
CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR)
OVL_HIDDEN_P (in OVERLOAD)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV) ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK) FN_TRY_BLOCK_P (in TRY_BLOCK)
...@@ -659,6 +660,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t; ...@@ -659,6 +660,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
/* If set, this was imported in a using declaration. */ /* If set, this was imported in a using declaration. */
#define OVL_USING_P(NODE) TREE_LANG_FLAG_1 (OVERLOAD_CHECK (NODE)) #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. */ /* If set, this overload contains a nested overload. */
#define OVL_NESTED_P(NODE) TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE)) #define OVL_NESTED_P(NODE) TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE))
/* If set, this overload was constructed during lookup. */ /* If set, this overload was constructed during lookup. */
...@@ -729,15 +732,26 @@ class ovl_iterator ...@@ -729,15 +732,26 @@ class ovl_iterator
{ {
return TREE_CODE (ovl) == OVERLOAD && OVL_USING_P (ovl); 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) tree remove_node (tree head)
{ {
return remove_node (head, ovl); return remove_node (head, ovl);
} }
tree reveal_node (tree head)
{
return reveal_node (head, ovl);
}
private: 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. */ iterator escaping the local context. */
static tree remove_node (tree head, tree node); 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 /* Iterator over a (potentially) 2 dimensional overload, which is
......
...@@ -1077,6 +1077,26 @@ strip_using_decl (tree decl) ...@@ -1077,6 +1077,26 @@ strip_using_decl (tree decl)
return 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. /* BINDING records an existing declaration for a name in the current scope.
But, DECL is another declaration for that same identifier in the But, DECL is another declaration for that same identifier in the
same scope. This is the `struct stat' hack whereby a non-typedef same scope. This is the `struct stat' hack whereby a non-typedef
...@@ -1131,9 +1151,7 @@ supplement_binding_1 (cxx_binding *binding, tree decl) ...@@ -1131,9 +1151,7 @@ supplement_binding_1 (cxx_binding *binding, tree decl)
|| target_bval == error_mark_node || target_bval == error_mark_node
/* If TARGET_BVAL is anticipated but has not yet been /* If TARGET_BVAL is anticipated but has not yet been
declared, pretend it is not there at all. */ declared, pretend it is not there at all. */
|| (TREE_CODE (target_bval) == FUNCTION_DECL || anticipated_builtin_p (target_bval))
&& DECL_ANTICIPATED (target_bval)
&& !DECL_HIDDEN_FRIEND_P (target_bval)))
binding->value = decl; binding->value = decl;
else if (TREE_CODE (target_bval) == TYPE_DECL else if (TREE_CODE (target_bval) == TYPE_DECL
&& DECL_ARTIFICIAL (target_bval) && DECL_ARTIFICIAL (target_bval)
...@@ -1803,7 +1821,7 @@ set_local_extern_decl_linkage (tree decl, bool shadowed) ...@@ -1803,7 +1821,7 @@ set_local_extern_decl_linkage (tree decl, bool shadowed)
loc_value = NULL_TREE; loc_value = NULL_TREE;
for (ovl_iterator iter (loc_value); iter; ++iter) for (ovl_iterator iter (loc_value); iter; ++iter)
if (!DECL_HIDDEN_P (*iter) if (!iter.hidden_p ()
&& (TREE_STATIC (*iter) || DECL_EXTERNAL (*iter)) && (TREE_STATIC (*iter) || DECL_EXTERNAL (*iter))
&& decls_match (*iter, decl)) && decls_match (*iter, decl))
{ {
...@@ -1931,15 +1949,34 @@ do_pushdecl (tree decl, bool is_friend) ...@@ -1931,15 +1949,34 @@ do_pushdecl (tree decl, bool is_friend)
if (iter.using_p ()) if (iter.using_p ())
; /* Ignore using decls here. */ ; /* Ignore using decls here. */
else if (tree match = duplicate_decls (decl, *iter, is_friend)) 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. */ /* We are pushing a new decl. */
/* Skip a hidden builtin we failed to match already. */ /* Skip a hidden builtin we failed to match already. There can
if (old && TREE_CODE (old) == FUNCTION_DECL only be one. */
&& DECL_ANTICIPATED (old) if (old && anticipated_builtin_p (old))
&& !DECL_HIDDEN_FRIEND_P (old)) old = OVL_CHAIN (old);
old = NULL_TREE;
check_template_shadow (decl); check_template_shadow (decl);
...@@ -3045,8 +3082,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p) ...@@ -3045,8 +3082,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
found = true; found = true;
else if (old.using_p ()) else if (old.using_p ())
continue; /* This is a using decl. */ continue; /* This is a using decl. */
else if (DECL_ANTICIPATED (old_fn) else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn))
&& !DECL_HIDDEN_FRIEND_P (old_fn))
continue; /* This is an anticipated builtin. */ continue; /* This is an anticipated builtin. */
else if (!matching_fn_p (new_fn, old_fn)) else if (!matching_fn_p (new_fn, old_fn))
continue; /* Parameters do not match. */ continue; /* Parameters do not match. */
...@@ -3069,9 +3105,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p) ...@@ -3069,9 +3105,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
} }
else if (value else if (value
/* Ignore anticipated builtins. */ /* Ignore anticipated builtins. */
&& !(TREE_CODE (value) == FUNCTION_DECL && !anticipated_builtin_p (value)
&& DECL_ANTICIPATED (value)
&& !DECL_HIDDEN_FRIEND_P (value))
&& !decls_match (lookup.value, value)) && !decls_match (lookup.value, value))
diagnose_name_conflict (lookup.value, value); diagnose_name_conflict (lookup.value, value);
else else
...@@ -5244,7 +5278,7 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p, ...@@ -5244,7 +5278,7 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p,
if (binding) 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 /* A non namespace-scope binding can only be hidden in the
presence of a local class, due to friend declarations. presence of a local class, due to friend declarations.
......
...@@ -2143,7 +2143,8 @@ ovl_copy (tree ovl) ...@@ -2143,7 +2143,8 @@ ovl_copy (tree ovl)
TREE_TYPE (result) = TREE_TYPE (ovl); TREE_TYPE (result) = TREE_TYPE (ovl);
OVL_FUNCTION (result) = OVL_FUNCTION (ovl); OVL_FUNCTION (result) = OVL_FUNCTION (ovl);
OVL_CHAIN (result) = OVL_CHAIN (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; return result;
} }
...@@ -2156,14 +2157,16 @@ tree ...@@ -2156,14 +2157,16 @@ tree
ovl_insert (tree fn, tree maybe_ovl, bool using_p) ovl_insert (tree fn, tree maybe_ovl, bool using_p)
{ {
bool copying = false; /* Checking use only. */ 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 result = NULL_TREE;
tree insert_after = NULL_TREE; tree insert_after = NULL_TREE;
/* Find insertion point. */ /* Find insertion point. */
while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD 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) gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl)
&& (!OVL_USED_P (maybe_ovl) || !copying)); && (!OVL_USED_P (maybe_ovl) || !copying));
...@@ -2181,9 +2184,11 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) ...@@ -2181,9 +2184,11 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p)
} }
tree trail = fn; 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); trail = ovl_make (fn, maybe_ovl);
if (hidden_p)
OVL_HIDDEN_P (trail) = true;
if (using_p) if (using_p)
OVL_USING_P (trail) = true; OVL_USING_P (trail) = true;
} }
...@@ -2199,6 +2204,28 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) ...@@ -2199,6 +2204,28 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p)
return result; 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 /* 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. OVL_USED_P we must copy OVL nodes, because those are immutable.
The removed node is unaltered and may continue to be iterated The removed node is unaltered and may continue to be iterated
......
2017-05-23 Nathan Sidwell <nathan@acm.org> 2017-05-23 Nathan Sidwell <nathan@acm.org>
* g++.dg/lookup/extern-c-hidden.C: New.
* g++.dg/lookup/extern-redecl1.C: New.
PR c++/80866 PR c++/80866
* g++.dg/parse/pr80866.C: New. * g++.dg/parse/pr80866.C: New.
......
// 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" }
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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment