aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl.c19
-rw-r--r--gcc/cp/name-lookup.c291
-rw-r--r--gcc/cp/name-lookup.h7
-rw-r--r--gcc/cp/tree.c30
5 files changed, 213 insertions, 136 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b7f5b6b..a25934e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7371,7 +7371,7 @@ inline tree ovl_first (tree) ATTRIBUTE_PURE;
extern tree ovl_make (tree fn,
tree next = NULL_TREE);
extern tree ovl_insert (tree fn, tree maybe_ovl,
- bool using_p = false);
+ int using_or_hidden = 0);
extern tree ovl_skip_hidden (tree) ATTRIBUTE_PURE;
extern void lookup_mark (tree lookup, bool val);
extern tree lookup_add (tree fns, tree lookup);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c00b996..617b96e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -15089,22 +15089,9 @@ xref_tag_1 (enum tag_types tag_code, tree name,
return error_mark_node;
}
- if (how != TAG_how::HIDDEN_FRIEND && TYPE_HIDDEN_P (t))
- {
- /* This is no longer an invisible friend. Make it
- visible. */
- tree decl = TYPE_NAME (t);
-
- DECL_ANTICIPATED (decl) = false;
- DECL_FRIEND_P (decl) = false;
-
- if (TYPE_TEMPLATE_INFO (t))
- {
- tree tmpl = TYPE_TI_TEMPLATE (t);
- DECL_ANTICIPATED (tmpl) = false;
- DECL_FRIEND_P (tmpl) = false;
- }
- }
+ gcc_checking_assert (how == TAG_how::HIDDEN_FRIEND
+ || !(DECL_LANG_SPECIFIC (TYPE_NAME (t))
+ && DECL_ANTICIPATED (TYPE_NAME (t))));
}
return t;
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 89f1a4c..bc60d343 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -55,6 +55,15 @@ static name_hint suggest_alternatives_for_1 (location_t location, tree name,
#define MAYBE_STAT_DECL(N) (STAT_HACK_P (N) ? STAT_DECL (N) : N)
#define MAYBE_STAT_TYPE(N) (STAT_HACK_P (N) ? STAT_TYPE (N) : NULL_TREE)
+/* For regular (maybe) overloaded functions, we have OVL_HIDDEN_P.
+ But we also need to indicate hiddenness on implicit type decls
+ (injected friend classes), and (coming soon) decls injected from
+ block-scope externs. It is too awkward to press the existing
+ overload marking for that. If we have a hidden non-function, we
+ always create a STAT_HACK, and use these two markers as needed. */
+#define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N)
+#define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N)
+
/* Create a STAT_HACK node with DECL as the value binding and TYPE as
the type binding. */
@@ -545,14 +554,18 @@ name_lookup::search_namespace_only (tree scope)
{
type = STAT_TYPE (value);
value = STAT_DECL (value);
-
- if (!bool (want & LOOK_want::HIDDEN_FRIEND)
- && DECL_LANG_SPECIFIC (type)
- && DECL_ANTICIPATED (type))
- type = NULL_TREE;
+
+ if (!bool (want & LOOK_want::HIDDEN_FRIEND))
+ {
+ if (STAT_TYPE_HIDDEN_P (*binding))
+ type = NULL_TREE;
+ if (STAT_DECL_HIDDEN_P (*binding))
+ value = NULL_TREE;
+ else
+ value = ovl_skip_hidden (value);
+ }
}
-
- if (!bool (want & LOOK_want::HIDDEN_FRIEND))
+ else if (!bool (want & LOOK_want::HIDDEN_FRIEND))
value = ovl_skip_hidden (value);
found |= process_binding (value, type);
@@ -1975,6 +1988,7 @@ cxx_binding_make (tree value, tree type)
/* Clear flags by default. */
LOCAL_BINDING_P (binding) = false;
INHERITED_VALUE_BINDING_P (binding) = false;
+ HIDDEN_TYPE_BINDING_P (binding) = false;
cxx_binding_init (binding, value, type);
@@ -2046,13 +2060,15 @@ pop_local_binding (tree id, tree decl)
/* The name should be bound. */
gcc_assert (binding != NULL);
- /* The DECL will be either the ordinary binding or the type
- binding for this identifier. Remove that binding. */
+ /* The DECL will be either the ordinary binding or the type binding
+ for this identifier. Remove that binding. We don't have to
+ clear HIDDEN_TYPE_BINDING_P, as the whole binding will be going
+ away. */
if (binding->value == decl)
binding->value = NULL_TREE;
else
{
- gcc_assert (binding->type == decl);
+ gcc_checking_assert (binding->type == decl);
binding->type = NULL_TREE;
}
@@ -2367,11 +2383,22 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
tree old, tree decl, bool hiding = false)
{
tree old_type = NULL_TREE;
+ bool hide_type = false;
+ bool hide_value = false;
if (!slot)
- old_type = binding->type;
+ {
+ old_type = binding->type;
+ hide_type = HIDDEN_TYPE_BINDING_P (binding);
+ if (!old_type)
+ hide_value = hide_type, hide_type = false;
+ }
else if (STAT_HACK_P (*slot))
+ {
old_type = STAT_TYPE (*slot);
+ hide_type = STAT_TYPE_HIDDEN_P (*slot);
+ hide_value = STAT_DECL_HIDDEN_P (*slot);
+ }
tree to_val = decl;
tree to_type = old_type;
@@ -2394,9 +2421,12 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
{
/* Put DECL into the type slot. */
gcc_checking_assert (!to_type);
+ hide_type = hiding;
to_type = decl;
to_val = old;
}
+ else
+ hide_value = hiding;
goto done;
}
@@ -2407,7 +2437,9 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
gcc_checking_assert (!to_type);
to_type = old;
+ hide_type = hide_value;
old = NULL_TREE;
+ hide_value = false;
}
if (DECL_DECLARES_FUNCTION_P (decl))
@@ -2450,7 +2482,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
decl, to_type);
local_overload = old && level->kind != sk_namespace;
- to_val = ovl_insert (decl, old);
+ to_val = ovl_insert (decl, old, -int (hiding));
}
else if (old)
{
@@ -2483,11 +2515,13 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
{
/* There can be two block-scope declarations of the same
variable, so long as they are `extern' declarations. */
- // FIXME: This is DECL_LOCAL_DECL_P type stuff.
if (!DECL_EXTERNAL (old) || !DECL_EXTERNAL (decl))
goto conflict;
else if (tree match = duplicate_decls (decl, old))
- return match;
+ {
+ gcc_checking_assert (!hide_value && !hiding);
+ return match;
+ }
else
goto conflict;
}
@@ -2498,6 +2532,8 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
to_val = NULL_TREE;
}
}
+ else if (hiding)
+ hide_value = true;
done:
if (to_val)
@@ -2516,16 +2552,26 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
{
STAT_TYPE (*slot) = to_type;
STAT_DECL (*slot) = to_val;
+ STAT_TYPE_HIDDEN_P (*slot) = hide_type;
+ STAT_DECL_HIDDEN_P (*slot) = hide_value;
+ }
+ else if (to_type || hide_value)
+ {
+ *slot = stat_hack (to_val, to_type);
+ STAT_TYPE_HIDDEN_P (*slot) = hide_type;
+ STAT_DECL_HIDDEN_P (*slot) = hide_value;
}
- else if (to_type)
- *slot = stat_hack (to_val, to_type);
else
- *slot = to_val;
+ {
+ gcc_checking_assert (!hide_type);
+ *slot = to_val;
+ }
}
else
{
binding->type = to_type;
binding->value = to_val;
+ HIDDEN_TYPE_BINDING_P (binding) = hide_type || hide_value;
}
}
@@ -6489,86 +6535,37 @@ lookup_name_1 (tree name, LOOK_where where, LOOK_want want)
for (cxx_binding *iter = nullptr;
(iter = outer_binding (name, iter, bool (where & LOOK_where::CLASS)));)
{
- tree binding;
-
/* Skip entities we don't want. */
if (!bool (where & (LOCAL_BINDING_P (iter)
? LOOK_where::BLOCK : LOOK_where::CLASS)))
continue;
/* If this is the kind of thing we're looking for, we're done. */
- if (iter->value
- && (bool (want & LOOK_want::HIDDEN_LAMBDA)
- || !is_lambda_ignored_entity (iter->value))
- && qualify_lookup (iter->value, want))
- binding = iter->value;
- else if (bool (want & LOOK_want::TYPE)
- && qualify_lookup (iter->type, want))
- binding = iter->type;
- else
- binding = NULL_TREE;
-
- if (binding)
+ if (iter->value)
{
- if (TREE_CODE (binding) == TYPE_DECL && DECL_HIDDEN_P (binding))
+ tree binding = NULL_TREE;
+
+ if (!(!iter->type && HIDDEN_TYPE_BINDING_P (iter))
+ && (bool (want & LOOK_want::HIDDEN_LAMBDA)
+ || !is_lambda_ignored_entity (iter->value))
+ && qualify_lookup (iter->value, want))
+ binding = iter->value;
+ else if (bool (want & LOOK_want::TYPE)
+ && !HIDDEN_TYPE_BINDING_P (iter)
+ && iter->type)
+ binding = iter->type;
+
+ if (binding)
{
- /* A non namespace-scope binding can only be hidden in the
- presence of a local class, due to friend declarations.
-
- In particular, consider:
-
- struct C;
- void f() {
- struct A {
- friend struct B;
- friend struct C;
- void g() {
- B* b; // error: B is hidden
- C* c; // OK, finds ::C
- }
- };
- B *b; // error: B is hidden
- C *c; // OK, finds ::C
- struct B {};
- B *bb; // OK
- }
-
- The standard says that "B" is a local class in "f"
- (but not nested within "A") -- but that name lookup
- for "B" does not find this declaration until it is
- declared directly with "f".
-
- In particular:
-
- [class.friend]
-
- If a friend declaration appears in a local class and
- the name specified is an unqualified name, a prior
- declaration is looked up without considering scopes
- that are outside the innermost enclosing non-class
- scope. For a friend function declaration, if there is
- no prior declaration, the program is ill-formed. For a
- friend class declaration, if there is no prior
- declaration, the class that is specified belongs to the
- innermost enclosing non-class scope, but if it is
- subsequently referenced, its name is not found by name
- lookup until a matching declaration is provided in the
- innermost enclosing nonclass scope.
-
- So just keep looking for a non-hidden binding.
- */
- gcc_assert (TREE_CODE (binding) == TYPE_DECL);
- continue;
+ /* The saved lookups for an operator record 'nothing
+ found' as error_mark_node. We need to stop the search
+ here, but not return the error mark node. */
+ if (binding == error_mark_node)
+ binding = NULL_TREE;
+
+ val = binding;
+ goto found;
}
-
- /* The saved lookups for an operator record 'nothing
- found' as error_mark_node. We need to stop the search
- here, but not return the error mark node. */
- if (binding == error_mark_node)
- binding = NULL_TREE;
-
- val = binding;
- goto found;
}
}
@@ -6649,17 +6646,55 @@ lookup_elaborated_type_1 (tree name, TAG_how how)
typedef struct C {} C;
correctly. */
+ tree found = NULL_TREE;
+ bool reveal = false;
if (tree type = iter->type)
- if (qualify_lookup (type, LOOK_want::TYPE)
- && (how != TAG_how::CURRENT_ONLY
- || LOCAL_BINDING_P (iter)
- || DECL_CONTEXT (type) == iter->scope->this_entity))
- return type;
-
- if (qualify_lookup (iter->value, LOOK_want::TYPE)
- && (how != TAG_how::CURRENT_ONLY
- || !INHERITED_VALUE_BINDING_P (iter)))
- return iter->value;
+ {
+ if (qualify_lookup (type, LOOK_want::TYPE)
+ && (how != TAG_how::CURRENT_ONLY
+ || LOCAL_BINDING_P (iter)
+ || DECL_CONTEXT (type) == iter->scope->this_entity))
+ {
+ found = type;
+ if (how != TAG_how::HIDDEN_FRIEND)
+ reveal = HIDDEN_TYPE_BINDING_P (iter);
+ }
+ }
+ else
+ {
+ if (qualify_lookup (iter->value, LOOK_want::TYPE)
+ && (how != TAG_how::CURRENT_ONLY
+ || !INHERITED_VALUE_BINDING_P (iter)))
+ {
+ found = iter->value;
+ if (how != TAG_how::HIDDEN_FRIEND)
+ reveal = !iter->type && HIDDEN_TYPE_BINDING_P (iter);
+ }
+ }
+
+ if (found)
+ {
+ if (reveal)
+ {
+ /* It is no longer a hidden binding. */
+ HIDDEN_TYPE_BINDING_P (iter) = false;
+
+ /* Unanticipate the decl itself. */
+ DECL_ANTICIPATED (found) = false;
+ DECL_FRIEND_P (found) = false;
+
+ gcc_checking_assert (TREE_CODE (found) != TEMPLATE_DECL);
+
+ if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found)))
+ {
+ tree tmpl = TI_TEMPLATE (ti);
+ DECL_ANTICIPATED (tmpl) = false;
+ DECL_FRIEND_P (tmpl) = false;
+ }
+ }
+
+ return found;
+ }
}
/* Now check if we can look in namespace scope. */
@@ -6675,13 +6710,63 @@ lookup_elaborated_type_1 (tree name, TAG_how how)
if (tree *slot = find_namespace_slot (ns, name))
{
/* If this is the kind of thing we're looking for, we're done. */
+ tree found = NULL_TREE;
+ bool reveal = false;
+
if (tree type = MAYBE_STAT_TYPE (*slot))
- if (qualify_lookup (type, LOOK_want::TYPE))
- return type;
+ {
+ found = type;
+ if (how != TAG_how::HIDDEN_FRIEND)
+ {
+ reveal = STAT_TYPE_HIDDEN_P (*slot);
+ STAT_TYPE_HIDDEN_P (*slot) = false;
+ }
+ }
+ else if (tree decl = MAYBE_STAT_DECL (*slot))
+ {
+ if (qualify_lookup (decl, LOOK_want::TYPE))
+ {
+ found = decl;
+
+ if (how != TAG_how::HIDDEN_FRIEND && STAT_HACK_P (*slot))
+ {
+ reveal = STAT_DECL_HIDDEN_P (*slot);
+ if (reveal)
+ {
+ if (STAT_TYPE (*slot))
+ STAT_DECL_HIDDEN_P (*slot) = false;
+ else
+ /* There is no type, just remove the stat
+ hack. */
+ *slot = decl;
+ }
+ }
+ }
+ }
+
+ if (found)
+ {
+ if (reveal)
+ {
+ /* Reveal the previously hidden thing. */
+ DECL_ANTICIPATED (found) = false;
+ DECL_FRIEND_P (found) = false;
+
+ if (TREE_CODE (found) == TEMPLATE_DECL)
+ {
+ DECL_ANTICIPATED (DECL_TEMPLATE_RESULT (found)) = false;
+ DECL_FRIEND_P (DECL_TEMPLATE_RESULT (found)) = false;
+ }
+ else if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found)))
+ {
+ tree tmpl = TI_TEMPLATE (ti);
+ DECL_ANTICIPATED (tmpl) = false;
+ DECL_FRIEND_P (tmpl) = false;
+ }
+ }
- if (tree decl = MAYBE_STAT_DECL (*slot))
- if (qualify_lookup (decl, LOOK_want::TYPE))
- return decl;
+ return found;
+ }
}
return NULL_TREE;
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 7b46338..01643fb 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -58,6 +58,12 @@ struct cp_binding_level;
currently being defined. */
#define INHERITED_VALUE_BINDING_P(NODE) ((NODE)->value_is_inherited)
+/* The IMPLICIT_TYPEDEF is hidden from ordinary name lookup (it was
+ injected via a local class's friend decl). The typdef may be in the
+ VALUE or the TYPE slot. We do not get the situation where the
+ value and type slots are both filled and both hidden. */
+#define HIDDEN_TYPE_BINDING_P(NODE) ((NODE)->type_is_hidden)
+
/* Datatype that represents binding established by a declaration between
a name and a C++ entity. */
struct GTY(()) cxx_binding {
@@ -72,6 +78,7 @@ struct GTY(()) cxx_binding {
bool value_is_inherited : 1;
bool is_local : 1;
+ bool type_is_hidden : 1;
};
/* Datatype used to temporarily save C++ bindings (for implicit
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index e860660..0b80d8e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2237,13 +2237,13 @@ ovl_make (tree fn, tree next)
return result;
}
-/* Add FN to the (potentially NULL) overload set OVL. USING_P is
- true, if FN is via a using declaration. We also pay attention to
- DECL_HIDDEN. We keep the hidden decls first, but remaining ones
- are unordered. */
+/* Add FN to the (potentially NULL) overload set OVL. USING_OR_HIDDEN
+ is > 0, if FN is via a using declaration. USING_OR_HIDDEN is < 0,
+ if FN is hidden. (A decl cannot be both using and hidden.) We
+ keep the hidden decls first, but remaining ones are unordered. */
tree
-ovl_insert (tree fn, tree maybe_ovl, bool using_p)
+ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden)
{
tree result = maybe_ovl;
tree insert_after = NULL_TREE;
@@ -2257,13 +2257,15 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p)
insert_after = maybe_ovl;
}
- bool hidden_p = DECL_HIDDEN_P (fn);
- if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL)
+ if (maybe_ovl || using_or_hidden || TREE_CODE (fn) == TEMPLATE_DECL)
{
maybe_ovl = ovl_make (fn, maybe_ovl);
- if (hidden_p)
+
+ gcc_checking_assert ((using_or_hidden < 0) == DECL_HIDDEN_P (fn));
+
+ if (using_or_hidden < 0)
OVL_HIDDEN_P (maybe_ovl) = true;
- if (using_p)
+ if (using_or_hidden > 0)
OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true;
}
else
@@ -2290,13 +2292,9 @@ ovl_skip_hidden (tree ovl)
ovl = OVL_CHAIN (ovl))
gcc_checking_assert (DECL_HIDDEN_P (OVL_FUNCTION (ovl)));
- if (ovl && TREE_CODE (ovl) != OVERLOAD && DECL_HIDDEN_P (ovl))
- {
- /* Any hidden functions should have been wrapped in an
- overload, but injected friend classes will not. */
- gcc_checking_assert (!DECL_DECLARES_FUNCTION_P (ovl));
- ovl = NULL_TREE;
- }
+ /* We should not see a naked hidden decl. */
+ gcc_checking_assert (!(ovl && TREE_CODE (ovl) != OVERLOAD
+ && DECL_HIDDEN_P (ovl)));
return ovl;
}