diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/cp-gimplify.c | 26 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 6 | ||||
-rw-r--r-- | gcc/cp/decl.c | 3 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 25 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 186 | ||||
-rw-r--r-- | gcc/cp/name-lookup.h | 1 | ||||
-rw-r--r-- | gcc/cp/parser.c | 14 | ||||
-rw-r--r-- | gcc/cp/pt.c | 14 |
8 files changed, 130 insertions, 145 deletions
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 0754982..44c9d24 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -980,21 +980,17 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) /* Map block scope extern declarations to visible declarations with the same name and type in outer scopes if any. */ - if (cp_function_chain->extern_decl_map - && VAR_OR_FUNCTION_DECL_P (stmt) - && DECL_EXTERNAL (stmt)) - { - struct cxx_int_tree_map *h, in; - in.uid = DECL_UID (stmt); - h = cp_function_chain->extern_decl_map->find_with_hash (&in, in.uid); - if (h) - { - *stmt_p = h->to; - TREE_USED (h->to) |= TREE_USED (stmt); - *walk_subtrees = 0; - return NULL; - } - } + if (VAR_OR_FUNCTION_DECL_P (stmt) && DECL_LOCAL_DECL_P (stmt)) + if (tree alias = DECL_LOCAL_DECL_ALIAS (stmt)) + { + if (alias != error_mark_node) + { + *stmt_p = alias; + TREE_USED (alias) |= TREE_USED (stmt); + } + *walk_subtrees = 0; + return NULL; + } if (TREE_CODE (stmt) == INTEGER_CST && TYPE_REF_P (TREE_TYPE (stmt)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e5a2ff2..4672561 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1926,7 +1926,6 @@ struct GTY(()) language_function { /* Tracking possibly infinite loops. This is a vec<tree> only because vec<bool> doesn't work with gtype. */ vec<tree, va_gc> *infinite_loops; - hash_table<cxx_int_tree_map_hasher> *extern_decl_map; }; /* The current C++-specific per-function global variables. */ @@ -2697,6 +2696,7 @@ struct GTY(()) lang_decl_min { In a lambda-capture proxy VAR_DECL, this is DECL_CAPTURED_VARIABLE. In a function-scope TREE_STATIC VAR_DECL or IMPLICIT_TYPEDEF_P TYPE_DECL, this is DECL_DISCRIMINATOR. + In a DECL_LOCAL_DECL_P decl, this is the namespace decl it aliases. Otherwise, in a class-scope DECL, this is DECL_ACCESS. */ tree access; }; @@ -4023,6 +4023,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_LOCAL_DECL_P(NODE) \ DECL_LANG_FLAG_0 (VAR_OR_FUNCTION_DECL_CHECK (NODE)) +/* The namespace-scope decl a DECL_LOCAL_DECL_P aliases. */ +#define DECL_LOCAL_DECL_ALIAS(NODE) \ + DECL_ACCESS ((gcc_checking_assert (DECL_LOCAL_DECL_P (NODE)), NODE)) + /* Nonzero if NODE is the target for genericization of 'return' stmts in constructors/destructors of targetm.cxx.cdtor_returns_this targets. */ #define LABEL_DECL_CDTOR(NODE) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4ec1f4a..0fe74b2 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5830,7 +5830,8 @@ layout_var_decl (tree decl) && DECL_SIZE (decl) != NULL_TREE && ! TREE_CONSTANT (DECL_SIZE (decl))) { - if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) + if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST + && !DECL_LOCAL_DECL_P (decl)) constant_expression_warning (DECL_SIZE (decl)); else { diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index fd48a21..db3035d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -5567,6 +5567,22 @@ mark_used (tree decl, tsubst_flags_t complain) return false; } + if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl)) + { + if (!DECL_LANG_SPECIFIC (decl)) + /* An unresolved dependent local extern. */ + return true; + + DECL_ODR_USED (decl) = 1; + auto alias = DECL_LOCAL_DECL_ALIAS (decl); + if (!alias || alias == error_mark_node) + return true; + + /* Process the underlying decl. */ + decl = alias; + TREE_USED (decl) = true; + } + cp_warn_deprecated_use (decl, complain); /* We can only check DECL_ODR_USED on variables or functions with @@ -5650,14 +5666,7 @@ mark_used (tree decl, tsubst_flags_t complain) && !DECL_ARTIFICIAL (decl) && !decl_defined_p (decl) && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)) - { - if (is_local_extern (decl)) - /* There's no way to define a local extern, and adding it to - the vector interferes with GC, so give an error now. */ - no_linkage_error (decl); - else - vec_safe_push (no_linkage_decls, decl); - } + vec_safe_push (no_linkage_decls, decl); if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index ea0bfdc..e3f3712 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see static cxx_binding *cxx_binding_make (tree value, tree type); static cp_binding_level *innermost_nonclass_level (void); +static tree do_pushdecl_with_scope (tree x, cp_binding_level *, bool hiding); static void set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b); static name_hint maybe_suggest_missing_std_header (location_t location, @@ -2921,108 +2922,66 @@ set_decl_context_in_fn (tree ctx, tree decl) DECL_CONTEXT (decl) = ctx; } -/* DECL is a local-scope decl with linkage. SHADOWED is true if the - name is already bound at the current level. - - [basic.link] If there is a visible declaration of an entity with - linkage having the same name and type, ignoring entities declared - outside the innermost enclosing namespace scope, the block scope - declaration declares that same entity and receives the linkage of - the previous declaration. - - Also, make sure that this decl matches any existing external decl - in the enclosing namespace. */ +/* DECL is a local extern decl. Find or create the namespace-scope + decl that it aliases. Also, determines the linkage of DECL. */ static void -set_local_extern_decl_linkage (tree decl, bool shadowed) +push_local_extern_decl_alias (tree decl) { - tree ns_value = decl; /* Unique marker. */ - - if (!shadowed) - { - tree loc_value = innermost_non_namespace_value (DECL_NAME (decl)); - if (!loc_value) - { - ns_value - = find_namespace_value (current_namespace, DECL_NAME (decl)); - loc_value = ns_value; - } - if (loc_value == error_mark_node - /* An ambiguous lookup. */ - || (loc_value && TREE_CODE (loc_value) == TREE_LIST)) - loc_value = NULL_TREE; - - for (ovl_iterator iter (loc_value); iter; ++iter) - if (!iter.hidden_p () - && (TREE_STATIC (*iter) || DECL_EXTERNAL (*iter)) - && decls_match (*iter, decl)) - { - /* The standard only says that the local extern inherits - linkage from the previous decl; in particular, default - args are not shared. Add the decl into a hash table to - make sure only the previous decl in this case is seen - by the middle end. */ - struct cxx_int_tree_map *h; - - /* We inherit the outer decl's linkage. But we're a - different decl. */ - TREE_PUBLIC (decl) = TREE_PUBLIC (*iter); - - if (cp_function_chain->extern_decl_map == NULL) - cp_function_chain->extern_decl_map - = hash_table<cxx_int_tree_map_hasher>::create_ggc (20); - - h = ggc_alloc<cxx_int_tree_map> (); - h->uid = DECL_UID (decl); - h->to = *iter; - cxx_int_tree_map **loc = cp_function_chain->extern_decl_map - ->find_slot (h, INSERT); - *loc = h; - break; - } - } + if (dependent_type_p (TREE_TYPE (decl))) + return; + /* EH specs were not part of the function type prior to c++17, but + we still can't go pushing dependent eh specs into the namespace. */ + if (cxx_dialect < cxx17 + && TREE_CODE (decl) == FUNCTION_DECL + && (value_dependent_expression_p + (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl))))) + return; - if (TREE_PUBLIC (decl)) - { - /* DECL is externally visible. Make sure it matches a matching - decl in the namespace scope. We only really need to check - this when inserting the decl, not when we find an existing - match in the current scope. However, in practice we're - going to be inserting a new decl in the majority of cases -- - who writes multiple extern decls for the same thing in the - same local scope? Doing it here often avoids a duplicate - namespace lookup. */ + gcc_checking_assert (!DECL_LANG_SPECIFIC (decl) + || !DECL_TEMPLATE_INFO (decl)); + if (DECL_LANG_SPECIFIC (decl) && DECL_LOCAL_DECL_ALIAS (decl)) + /* We're instantiating a non-dependent local decl, it already + knows the alias. */ + return; - /* Avoid repeating a lookup. */ - if (ns_value == decl) - ns_value = find_namespace_value (current_namespace, DECL_NAME (decl)); + tree alias = NULL_TREE; - if (ns_value == error_mark_node - || (ns_value && TREE_CODE (ns_value) == TREE_LIST)) - ns_value = NULL_TREE; + if (DECL_SIZE (decl) && !TREE_CONSTANT (DECL_SIZE (decl))) + /* Do not let a VLA creep into a namespace. Diagnostic will be + emitted in layout_var_decl later. */ + alias = error_mark_node; + else + { + /* First look for a decl that matches. */ + tree ns = CP_DECL_CONTEXT (decl); + tree binding = find_namespace_value (ns, DECL_NAME (decl)); - for (ovl_iterator iter (ns_value); iter; ++iter) - { - tree other = *iter; - - if (!(TREE_PUBLIC (other) || DECL_EXTERNAL (other))) - ; /* Not externally visible. */ - else if (DECL_EXTERN_C_P (decl) && DECL_EXTERN_C_P (other)) - ; /* Both are extern "C", we'll check via that mechanism. */ - else if (TREE_CODE (other) != TREE_CODE (decl) - || ((VAR_P (decl) || matching_fn_p (other, decl)) - && !comptypes (TREE_TYPE (decl), TREE_TYPE (other), - COMPARE_REDECLARATION))) + if (binding && TREE_CODE (binding) != TREE_LIST) + for (ovl_iterator iter (binding); iter; ++iter) + if (decls_match (*iter, decl)) { - auto_diagnostic_group d; - if (permerror (DECL_SOURCE_LOCATION (decl), - "local external declaration %q#D", decl)) - inform (DECL_SOURCE_LOCATION (other), - "does not match previous declaration %q#D", other); + alias = *iter; break; } + + if (!alias) + { + /* No existing namespace-scope decl. Make one. */ + alias = copy_decl (decl); + + /* This is the real thing. */ + DECL_LOCAL_DECL_P (alias) = false; + + /* Expected default linkage is from the namespace. */ + TREE_PUBLIC (alias) = TREE_PUBLIC (ns); + alias = do_pushdecl_with_scope (alias, NAMESPACE_LEVEL (ns), + /* hiding= */true); } } + + retrofit_lang_decl (decl); + DECL_LOCAL_DECL_ALIAS (decl) = alias; } /* Record DECL as belonging to the current lexical scope. Check for @@ -3080,10 +3039,6 @@ do_pushdecl (tree decl, bool hiding) old = binding->value; } - if (current_function_decl && VAR_OR_FUNCTION_DECL_P (decl) - && DECL_EXTERNAL (decl)) - set_local_extern_decl_linkage (decl, old != NULL_TREE); - if (old == error_mark_node) old = NULL_TREE; @@ -3115,6 +3070,16 @@ do_pushdecl (tree decl, bool hiding) /* We need to check and register the decl now. */ check_extern_c_conflict (match); } + else if (slot && !hiding + && STAT_HACK_P (*slot) && STAT_DECL_HIDDEN_P (*slot)) + { + /* Unhide the non-function. */ + gcc_checking_assert (old == match); + if (!STAT_TYPE (*slot)) + *slot = match; + else + STAT_DECL (*slot) = match; + } return match; } @@ -3190,12 +3155,21 @@ do_pushdecl (tree decl, bool hiding) if (!instantiating_current_function_p ()) record_locally_defined_typedef (decl); } - else if (VAR_P (decl)) - maybe_register_incomplete_var (decl); + else + { + if (VAR_P (decl) && !DECL_LOCAL_DECL_P (decl)) + maybe_register_incomplete_var (decl); + + if (VAR_OR_FUNCTION_DECL_P (decl)) + { + if (DECL_LOCAL_DECL_P (decl) + && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) + push_local_extern_decl_alias (decl); - if ((VAR_P (decl) || TREE_CODE (decl) == FUNCTION_DECL) - && DECL_EXTERN_C_P (decl)) - check_extern_c_conflict (decl); + if (DECL_EXTERN_C_P (decl)) + check_extern_c_conflict (decl); + } + } } else add_decl_to_level (level, decl); @@ -6871,20 +6845,6 @@ lookup_elaborated_type (tree name, TAG_how how) return ret; } -/* Returns true iff DECL is a block-scope extern declaration of a function - or variable. We will already have determined validity of the decl - when pushing it. So we do not have to redo that lookup. */ - -bool -is_local_extern (tree decl) -{ - if ((TREE_CODE (decl) == FUNCTION_DECL - || TREE_CODE (decl) == VAR_DECL)) - return DECL_LOCAL_DECL_P (decl); - - return false; -} - /* The type TYPE is being declared. If it is a class template, or a specialization of a class template, do any processing required and perform error-checking. If IS_FRIEND is nonzero, this TYPE is diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 01643fb..d63ff10 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -342,7 +342,6 @@ extern tree lookup_qualified_name (tree scope, tree name, extern tree lookup_qualified_name (tree scope, const char *name, LOOK_want = LOOK_want::NORMAL, bool = true); -extern bool is_local_extern (tree); extern bool pushdecl_class_level (tree); extern tree pushdecl_namespace_level (tree, bool hiding = false); extern bool push_class_level_binding (tree, tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 2002c05..7a61abf 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -41176,6 +41176,10 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok) } if (!found_in_scope) + /* This seems to ignore the existence of cleanup scopes? + What is the meaning for local extern decls? The local + extern is in this scope, but it is referring to a decl that + is namespace scope. */ for (tree d = current_binding_level->names; d; d = TREE_CHAIN (d)) if (d == decl) { @@ -41205,6 +41209,16 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok) { tree id; + if (DECL_LOCAL_DECL_P (decl)) + /* We need to mark the aliased decl, as that is the entity + that is being referred to. This won't work for + dependent variables, but it didn't work for them before + DECL_LOCAL_DECL_P was a thing either. But then + dependent local extern variable decls are as rare as + hen's teeth. */ + if (auto alias = DECL_LOCAL_DECL_ALIAS (decl)) + decl = alias; + if (OMP_CLAUSE_MAP_KIND (t) == GOMP_MAP_LINK) id = get_identifier ("omp declare target link"); else diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1ab5435..3755aab 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18104,13 +18104,15 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } else if (DECL_IMPLICIT_TYPEDEF_P (t)) /* We already did a pushtag. */; - else if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_LOCAL_DECL_P (decl) - && DECL_OMP_DECLARE_REDUCTION_P (decl)) + else if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LOCAL_DECL_P (decl)) { - DECL_CONTEXT (decl) = current_function_decl; - pushdecl (decl); - if (cp_check_omp_declare_reduction (decl)) + if (TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) + DECL_CONTEXT (decl) = NULL_TREE; + decl = pushdecl (decl); + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_OMP_DECLARE_REDUCTION_P (decl) + && cp_check_omp_declare_reduction (decl)) instantiate_body (pattern_decl, args, decl, true); } else |