From e4ea7a4cfe438d0bdbede4b714aba50df01a4a76 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 23 May 2017 16:03:34 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 7 + gcc/cp/cp-tree.h | 5 + gcc/cp/name-lookup.c | 218 ++++++++++++++++++----------- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/parse/ctor9.C | 2 +- 5 files changed, 153 insertions(+), 83 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bfe718fae78..2e2415c130e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2017-05-23 Nathan Sidwell + + * 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 * parser.c (OACC_KERNELS_CLAUSE_MASK): Add diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8e8e5606c78..bbb75d4c456 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)) \ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index c79ded333a0..388d02704e6 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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::create_ggc (20); + + h = ggc_alloc (); + 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::create_ggc (20); - - h = ggc_alloc (); - 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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d358f4b2183..9877c76a0e5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-05-23 Nathan Sidwell + + * g++.dg/parse/ctor9.C: Adjust expected error. + 2017-05-23 Jerry DeLisle PR libgfortran/80256 diff --git a/gcc/testsuite/g++.dg/parse/ctor9.C b/gcc/testsuite/g++.dg/parse/ctor9.C index 8b2cbf7a643..6df2595e144 100644 --- a/gcc/testsuite/g++.dg/parse/ctor9.C +++ b/gcc/testsuite/g++.dg/parse/ctor9.C @@ -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" } */ }; -- 2.30.2