+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
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)
/* 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. */
{
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
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
|| 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)
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))
{
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);
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. */
}
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
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.
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;
}
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));
}
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;
}
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.
--- /dev/null
+// 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" }
--- /dev/null
+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);
+}
+