diff options
-rw-r--r-- | gcc/cp/cp-tree.h | 2 | ||||
-rw-r--r-- | gcc/cp/decl.c | 19 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 291 | ||||
-rw-r--r-- | gcc/cp/name-lookup.h | 7 | ||||
-rw-r--r-- | gcc/cp/tree.c | 30 |
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; } |