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>
-Wunused and C++17 structured bindings
......
......@@ -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
......
......@@ -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.
......
......@@ -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
......
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
* 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