aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2017-05-24 11:28:54 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2017-05-24 11:28:54 +0000
commitef4c5e7855ea00a62487c0d34915d66946032172 (patch)
treede86db645e445af4e19f288d8422859e96b4e191 /gcc
parentb7fc9ae0aabaf8c95c524031659b0a17bf597c9e (diff)
downloadgcc-ef4c5e7855ea00a62487c0d34915d66946032172.zip
gcc-ef4c5e7855ea00a62487c0d34915d66946032172.tar.gz
gcc-ef4c5e7855ea00a62487c0d34915d66946032172.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog16
-rw-r--r--gcc/cp/cp-tree.h16
-rw-r--r--gcc/cp/name-lookup.c66
-rw-r--r--gcc/cp/tree.c35
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/lookup/extern-c-hidden.C11
-rw-r--r--gcc/testsuite/g++.dg/lookup/extern-redecl1.C18
7 files changed, 144 insertions, 21 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 785dfc5..16e30fa 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,19 @@
+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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2ed9e5a..7f1c632 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 89d4e2a..57d85a5 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 8490c81..5ae9601 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 f536dda..d8d16ee 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
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.
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 0000000..a03dea0
--- /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 0000000..18e675b
--- /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);
+}
+