cp-tree.h (DECL_HIDDEN_P): New.

gcc/cp/
	* cp-tree.h (DECL_HIDDEN_P): New.
	* name-lookup.c (set_decl_context)
	set_local_extern_decl_linkage):	New, broken out of ...
	(pushdecl_maybe_friend_1): ... here.  Call them.

	gcc/testsuite/
	* g++.dg/parse/ctor9.C: Adjust expected error.
(--This line, and those below, will be ignored--

M    cp/name-lookup.c
M    cp/ChangeLog
M    cp/cp-tree.h
M    testsuite/ChangeLog
M    testsuite/g++.dg/parse/ctor9.C

From-SVN: r248373
This commit is contained in:
Nathan Sidwell 2017-05-23 16:03:34 +00:00 committed by Nathan Sidwell
parent 8a4674bb23
commit e4ea7a4cfe
5 changed files with 153 additions and 83 deletions

View file

@ -1,3 +1,10 @@
2017-05-23 Nathan Sidwell <nathan@acm.org>
* cp-tree.h (DECL_HIDDEN_P): New.
* name-lookup.c (set_decl_context,
set_local_extern_decl_linkage): New, broken out of ...
(pushdecl_maybe_friend_1): ... here. Call them.
2017-05-23 Thomas Schwinge <thomas@codesourcery.com>
* parser.c (OACC_KERNELS_CLAUSE_MASK): Add

View file

@ -3775,6 +3775,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
(DECL_LANG_SPECIFIC (TYPE_FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)) \
->u.base.anticipated_p)
/* Is DECL NODE a hidden name? */
#define DECL_HIDDEN_P(NODE) \
(DECL_LANG_SPECIFIC (NODE) && TYPE_FUNCTION_OR_TEMPLATE_DECL_P (NODE) \
&& DECL_ANTICIPATED (NODE))
/* True if this is a hidden class type. */
#define TYPE_HIDDEN_P(NODE) \
(DECL_LANG_SPECIFIC (TYPE_NAME (NODE)) \

View file

@ -1534,6 +1534,137 @@ check_local_shadow (tree decl)
inform (DECL_SOURCE_LOCATION (shadowed), "shadowed declaration is here");
}
/* DECL is being pushed inside function CTX. Set its context, if
needed. */
static void
set_decl_context_in_fn (tree ctx, tree decl)
{
if (!DECL_CONTEXT (decl)
/* A local declaration for a function doesn't constitute
nesting. */
&& TREE_CODE (decl) != FUNCTION_DECL
/* A local declaration for an `extern' variable is in the
scope of the current namespace, not the current
function. */
&& !(VAR_P (decl) && DECL_EXTERNAL (decl))
/* When parsing the parameter list of a function declarator,
don't set DECL_CONTEXT to an enclosing function. When we
push the PARM_DECLs in order to process the function body,
current_binding_level->this_entity will be set. */
&& !(TREE_CODE (decl) == PARM_DECL
&& current_binding_level->kind == sk_function_parms
&& current_binding_level->this_entity == NULL))
DECL_CONTEXT (decl) = ctx;
/* If this is the declaration for a namespace-scope function,
but the declaration itself is in a local scope, mark the
declaration. */
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (decl))
DECL_LOCAL_FUNCTION_P (decl) = 1;
}
/* 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. */
static void
set_local_extern_decl_linkage (tree decl, bool shadowed)
{
tree ns_value = decl; /* Unique marker. */
if (!shadowed)
{
tree loc_value = innermost_non_namespace_value (DECL_NAME (decl));
if (!loc_value)
{
ns_value
= get_namespace_binding (current_namespace, DECL_NAME (decl));
loc_value = ns_value;
}
if (loc_value == error_mark_node)
loc_value = NULL_TREE;
for (ovl_iterator iter (loc_value); iter; ++iter)
if (!DECL_HIDDEN_P (*iter)
&& (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 (TREE_PUBLIC (decl))
{
/* DECL is externally visible. Make sure it matches a matching
decl in the namespace scpe. 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. */
/* Avoid repeating a lookup. */
if (ns_value == decl)
ns_value = get_namespace_binding (current_namespace, DECL_NAME (decl));
if (ns_value == error_mark_node)
ns_value = NULL_TREE;
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 (permerror (DECL_SOURCE_LOCATION (decl),
"local external declaration %q#D", decl))
inform (DECL_SOURCE_LOCATION (other),
"does not match previous declaration %q#D", other);
break;
}
}
}
}
/* Record a decl-node X as belonging to the current lexical scope.
Check for errors (such as an incompatible declaration for the same
name already seen in the same scope). IS_FRIEND is true if X is
@ -1555,45 +1686,12 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
need_new_binding = 1;
if (DECL_TEMPLATE_PARM_P (x))
/* Template parameters have no context; they are not X::T even
when declared within a class or namespace. */
;
else
{
if (current_function_decl && x != current_function_decl
/* A local declaration for a function doesn't constitute
nesting. */
&& TREE_CODE (x) != FUNCTION_DECL
/* A local declaration for an `extern' variable is in the
scope of the current namespace, not the current
function. */
&& !(VAR_P (x) && DECL_EXTERNAL (x))
/* When parsing the parameter list of a function declarator,
don't set DECL_CONTEXT to an enclosing function. When we
push the PARM_DECLs in order to process the function body,
current_binding_level->this_entity will be set. */
&& !(TREE_CODE (x) == PARM_DECL
&& current_binding_level->kind == sk_function_parms
&& current_binding_level->this_entity == NULL)
&& !DECL_CONTEXT (x))
DECL_CONTEXT (x) = current_function_decl;
/* If this is the declaration for a namespace-scope function,
but the declaration itself is in a local scope, mark the
declaration. */
if (TREE_CODE (x) == FUNCTION_DECL
&& DECL_NAMESPACE_SCOPE_P (x)
&& current_function_decl
&& x != current_function_decl)
DECL_LOCAL_FUNCTION_P (x) = 1;
}
if (!DECL_TEMPLATE_PARM_P (x) && current_function_decl)
set_decl_context_in_fn (current_function_decl, x);
name = DECL_NAME (x);
if (name)
{
int different_binding_level = 0;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
name = TREE_OPERAND (name, 0);
@ -1604,27 +1702,9 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
else
t = lookup_name_innermost_nonclass_level (name);
/* [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. */
if (! t && current_function_decl && x != current_function_decl
&& VAR_OR_FUNCTION_DECL_P (x)
if (current_function_decl && VAR_OR_FUNCTION_DECL_P (x)
&& DECL_EXTERNAL (x))
{
/* Look in block scope. */
t = innermost_non_namespace_value (name);
/* Or in the innermost namespace. */
if (! t)
t = get_namespace_binding (DECL_CONTEXT (x), name);
/* Does it have linkage? Note that if this isn't a DECL, it's an
OVERLOAD, which is OK. */
if (t && DECL_P (t) && ! (TREE_STATIC (t) || DECL_EXTERNAL (t)))
t = NULL_TREE;
if (t)
different_binding_level = 1;
}
set_local_extern_decl_linkage (x, t != NULL_TREE);
/* If we are declaring a function, and the result of name-lookup
was an OVERLOAD, look for an overloaded instance that is
@ -1653,33 +1733,7 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
if (t && t != error_mark_node)
{
if (different_binding_level)
{
if (decls_match (x, t))
/* 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;
TREE_PUBLIC (x) = TREE_PUBLIC (t);
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 (x);
h->to = t;
cxx_int_tree_map **loc = cp_function_chain->extern_decl_map
->find_slot (h, INSERT);
*loc = h;
}
}
else if (TREE_CODE (t) == PARM_DECL)
if (TREE_CODE (t) == PARM_DECL)
{
/* Check for duplicate params. */
tree d = duplicate_decls (x, t, is_friend);

View file

@ -1,3 +1,7 @@
2017-05-23 Nathan Sidwell <nathan@acm.org>
* g++.dg/parse/ctor9.C: Adjust expected error.
2017-05-23 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/80256

View file

@ -3,5 +3,5 @@
struct A
{
A() { void A(); } /* { dg-error "return type specification for constructor invalid|non-class scope" } */
A() { void A(); } /* { dg-error "return type specification for constructor invalid|non-class scope|local external" } */
};