aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/cp-gimplify.c26
-rw-r--r--gcc/cp/cp-tree.h6
-rw-r--r--gcc/cp/decl.c3
-rw-r--r--gcc/cp/decl2.c25
-rw-r--r--gcc/cp/name-lookup.c186
-rw-r--r--gcc/cp/name-lookup.h1
-rw-r--r--gcc/cp/parser.c14
-rw-r--r--gcc/cp/pt.c14
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