From 3a77e7ccc4cc096613394ab0ebb520ac71325405 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 15 May 2017 19:35:52 +0000 Subject: [PATCH] re PR c++/79369 (namespace definition with qualified id) gcc/cp/ PR c++/79369 * cp-tree.h (DECL_NAMESPACE_INLINE_P): New. * name-lookup.h (push_namespace): Return int, add make_inline arg. * name-lookup.c (push_namespace): Deal with inline directly. Return pushed count. * parser.c (cp_parser_namespace_definition): Adjust for push_namespace change. gcc/testsuite/ * g++.dg/cpp0x/pr65558.C: Adjust diagnostic location. * g++.dg/cpp0x/pr79369.C: New. From-SVN: r248073 --- gcc/cp/ChangeLog | 10 +++ gcc/cp/cp-tree.h | 5 ++ gcc/cp/name-lookup.c | 157 ++++++++++++++++++----------------- gcc/cp/name-lookup.h | 2 +- gcc/cp/parser.c | 122 +++++++++++---------------- gcc/testsuite/ChangeLog | 8 +- gcc/testsuite/g++.dg/cpp0x/pr65558.C | 5 +- gcc/testsuite/g++.dg/cpp0x/pr79369.C | 9 ++ 8 files changed, 164 insertions(+), 154 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr79369.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 94ad044..fe99fa7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2017-05-15 Nathan Sidwell + + PR c++/79369 + * cp-tree.h (DECL_NAMESPACE_INLINE_P): New. + * name-lookup.h (push_namespace): Return int, add make_inline arg. + * name-lookup.c (push_namespace): Deal with inline directly. + Return pushed count. + * parser.c (cp_parser_namespace_definition): Adjust for + push_namespace change. + 2017-05-11 Nathan Sidwell * cp-lang.c (get_global_decls, cxx_pushdecl, LANG_HOOK_GETDECLS, diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9596886..85cdf07 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -333,6 +333,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; FOLD_EXPR_MODOP_P (*_FOLD_EXPR) IF_STMT_CONSTEXPR_P (IF_STMT) TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM) + DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -2916,6 +2917,10 @@ struct GTY(()) lang_decl { #define LOCAL_CLASS_P(NODE) \ (decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE) +/* Whether the namepace is an inline namespace. */ +#define DECL_NAMESPACE_INLINE_P(NODE) \ + TREE_LANG_FLAG_0 (NAMESPACE_DECL_CHECK (NODE)) + /* For a NAMESPACE_DECL: the list of using namespace directives The PURPOSE is the used namespace, the value is the namespace that is the common ancestor. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 885ced5..375376a 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -6441,107 +6441,112 @@ pop_from_top_level (void) timevar_cond_stop (TV_NAME_LOOKUP, subtime); } -/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we - select a name that is unique to this compilation unit. Returns FALSE if - pushdecl fails, TRUE otherwise. */ +/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, + then we enter an anonymous namespace. If MAKE_INLINE is true, then + we create an inline namespace (it is up to the caller to check upon + redefinition). Return the number of namespaces entered. */ -bool -push_namespace (tree name) +int +push_namespace (tree name, bool make_inline) { - tree d = NULL_TREE; - bool need_new = true; - bool implicit_use = false; - bool anon = !name; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + int count = 0; /* We should not get here if the global_namespace is not yet constructed nor if NAME designates the global namespace: The global scope is constructed elsewhere. */ gcc_assert (global_namespace != NULL && name != global_identifier); - if (anon) - { - name = anon_identifier; - d = get_namespace_binding (current_namespace, name); - if (d) - /* Reopening anonymous namespace. */ - need_new = false; - implicit_use = true; - } - else + if (!name) + name = anon_identifier; + + /* Check whether this is an extended namespace definition. */ + tree ns = get_namespace_binding (current_namespace, name); + if (ns && TREE_CODE (ns) == NAMESPACE_DECL) { - /* Check whether this is an extended namespace definition. */ - d = get_namespace_binding (current_namespace, name); - if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL) + if (tree dna = DECL_NAMESPACE_ALIAS (ns)) { - tree dna = DECL_NAMESPACE_ALIAS (d); - if (dna) - { - /* We do some error recovery for, eg, the redeclaration - of M here: - - namespace N {} - namespace M = N; - namespace M {} - - However, in nasty cases like: - - namespace N - { - namespace M = N; - namespace M {} - } - - we just error out below, in duplicate_decls. */ - if (NAMESPACE_LEVEL (dna)->level_chain - == current_binding_level) - { - error ("namespace alias %qD not allowed here, " - "assuming %qD", d, dna); - d = dna; - need_new = false; - } + /* We do some error recovery for, eg, the redeclaration of M + here: + + namespace N {} + namespace M = N; + namespace M {} + + However, in nasty cases like: + + namespace N + { + namespace M = N; + namespace M {} + } + + we just error out below, in duplicate_decls. */ + if (NAMESPACE_LEVEL (dna)->level_chain == current_binding_level) + { + error ("namespace alias %qD not allowed here, " + "assuming %qD", ns, dna); + ns = dna; } else - need_new = false; + ns = NULL_TREE; } } + else + ns = NULL_TREE; - if (need_new) + bool new_ns = false; + if (!ns) { - /* Make a new namespace, binding the name to it. */ - d = build_lang_decl (NAMESPACE_DECL, name, void_type_node); - DECL_CONTEXT (d) = FROB_CONTEXT (current_namespace); - /* The name of this namespace is not visible to other translation - units if it is an anonymous namespace or member thereof. */ - if (anon || decl_anon_ns_mem_p (current_namespace)) - TREE_PUBLIC (d) = 0; + ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node); + DECL_CONTEXT (ns) = FROB_CONTEXT (current_namespace); + new_ns = true; + + if (pushdecl (ns) == error_mark_node) + ns = NULL_TREE; else - TREE_PUBLIC (d) = 1; - if (pushdecl (d) == error_mark_node) { - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return false; + if (name == anon_identifier) + { + /* Clear DECL_NAME for the benefit of debugging back ends. */ + SET_DECL_ASSEMBLER_NAME (ns, name); + DECL_NAME (ns) = NULL_TREE; + + if (!make_inline) + do_using_directive (ns); + } + else if (TREE_PUBLIC (current_namespace)) + TREE_PUBLIC (ns) = 1; + + if (make_inline) + { + DECL_NAMESPACE_INLINE_P (ns) = true; + /* Set up namespace association. */ + DECL_NAMESPACE_ASSOCIATIONS (ns) + = tree_cons (current_namespace, NULL_TREE, NULL_TREE); + /* Import the contents of the inline namespace. */ + do_using_directive (ns); + } } - if (anon) + } + + if (ns) + { + if (make_inline && !DECL_NAMESPACE_INLINE_P (ns)) { - /* Clear DECL_NAME for the benefit of debugging back ends. */ - SET_DECL_ASSEMBLER_NAME (d, name); - DECL_NAME (d) = NULL_TREE; + error ("inline namespace must be specified at initial definition"); + inform (DECL_SOURCE_LOCATION (ns), "%qD defined here", ns); } - begin_scope (sk_namespace, d); + if (new_ns) + begin_scope (sk_namespace, ns); + else + resume_scope (NAMESPACE_LEVEL (ns)); + current_namespace = ns; + count++; } - else - resume_scope (NAMESPACE_LEVEL (d)); - - if (implicit_use) - do_using_directive (d); - /* Enter the name space. */ - current_namespace = d; timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return true; + return count; } /* Pop from the scope of the current namespace. */ diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 9755884..824ea33 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -340,7 +340,7 @@ extern tree pushdecl (tree, bool is_friend = false); extern tree pushdecl_top_level (tree, bool is_friend = false); extern tree pushdecl_top_level_and_finish (tree, tree); extern tree pushtag (tree, tree, tag_scope); -extern bool push_namespace (tree); +extern int push_namespace (tree, bool make_inline = false); extern void pop_namespace (void); extern void push_nested_namespace (tree); extern void pop_nested_namespace (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f82a90c..99c742f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18172,114 +18172,88 @@ cp_parser_namespace_name (cp_parser* parser) static void cp_parser_namespace_definition (cp_parser* parser) { - tree identifier, attribs; - bool has_visibility; - bool is_inline; - cp_token* token; + tree identifier; int nested_definition_count = 0; cp_ensure_no_omp_declare_simd (parser); cp_ensure_no_oacc_routine (parser); - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE)) + + bool is_inline = cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE); + + if (is_inline) { maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES); - is_inline = true; cp_lexer_consume_token (parser->lexer); } - else - is_inline = false; /* Look for the `namespace' keyword. */ - token = cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE); + cp_token* token + = cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE); /* Parse any specified attributes before the identifier. */ - attribs = cp_parser_attributes_opt (parser); + tree attribs = cp_parser_attributes_opt (parser); - /* Get the name of the namespace. We do not attempt to distinguish - between an original-namespace-definition and an - extension-namespace-definition at this point. The semantic - analysis routines are responsible for that. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) - identifier = cp_parser_identifier (parser); - else - identifier = NULL_TREE; - - /* Parse any specified attributes after the identifier. */ - tree post_ident_attribs = cp_parser_attributes_opt (parser); - if (post_ident_attribs) + for (;;) { - if (attribs) - attribs = chainon (attribs, post_ident_attribs); - else - attribs = post_ident_attribs; - } + identifier = NULL_TREE; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + identifier = cp_parser_identifier (parser); - /* Start the namespace. */ - bool ok = push_namespace (identifier); + /* Parse any attributes specified after the identifier. */ + attribs = chainon (attribs, cp_parser_attributes_opt (parser)); + } - /* Parse any nested namespace definition. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) - { - if (attribs) - error_at (token->location, "a nested namespace definition cannot have attributes"); - if (cxx_dialect < cxx1z) + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE)) + break; + + if (!nested_definition_count && cxx_dialect < cxx1z) pedwarn (input_location, OPT_Wpedantic, "nested namespace definitions only available with " "-std=c++1z or -std=gnu++1z"); - if (is_inline) - error_at (token->location, "a nested namespace definition cannot be inline"); - while (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) - { - cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) - identifier = cp_parser_identifier (parser); - else - { - cp_parser_error (parser, "nested identifier required"); - break; - } - if (push_namespace (identifier)) - ++nested_definition_count; - } + + /* Nested namespace names can create new namespaces (unlike + other qualified-ids). */ + if (int count = identifier ? push_namespace (identifier) : 0) + nested_definition_count += count; + else + cp_parser_error (parser, "nested namespace name required"); + cp_lexer_consume_token (parser->lexer); } - /* Look for the `{' to validate starting the namespace. */ - cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); + if (nested_definition_count && !identifier) + cp_parser_error (parser, "namespace name required"); + + if (nested_definition_count && attribs) + error_at (token->location, + "a nested namespace definition cannot have attributes"); + if (nested_definition_count && is_inline) + error_at (token->location, + "a nested namespace definition cannot be inline"); - /* "inline namespace" is equivalent to a stub namespace definition - followed by a strong using directive. */ - if (is_inline && ok) - { - tree name_space = current_namespace; - /* Set up namespace association. */ - DECL_NAMESPACE_ASSOCIATIONS (name_space) - = tree_cons (CP_DECL_CONTEXT (name_space), NULL_TREE, - DECL_NAMESPACE_ASSOCIATIONS (name_space)); - /* Import the contents of the inline namespace. */ - pop_namespace (); - do_using_directive (name_space); - push_namespace (identifier); - } + /* Start the namespace. */ + nested_definition_count += push_namespace (identifier, is_inline); - has_visibility = handle_namespace_attrs (current_namespace, attribs); + bool has_visibility = handle_namespace_attrs (current_namespace, attribs); warning (OPT_Wnamespaces, "namespace %qD entered", current_namespace); + /* Look for the `{' to validate starting the namespace. */ + cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); + /* Parse the body of the namespace. */ cp_parser_namespace_body (parser); + /* Look for the final `}'. */ + cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + if (has_visibility) pop_visibility (1); - /* Finish the nested namespace definitions. */ + /* Pop the nested namespace definitions. */ while (nested_definition_count--) pop_namespace (); - - /* Finish the namespace. */ - if (ok) - pop_namespace (); - /* Look for the final `}'. */ - cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); } /* Parse a namespace-body. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0082e85..65fe9e3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,7 +1,13 @@ +2017-05-15 Nathan Sidwell + + PR c++/79369 + * g++.dg/cpp0x/pr65558.C: Adjust diagnostic location. + * g++.dg/cpp0x/pr79369.C: New. + 2017-05-15 Steven G. Kargl PR fortran/80752 - gfortran.dg/pr80752.f90: New test. + * gfortran.dg/pr80752.f90: New test. 2017-05-15 Uros Bizjak diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65558.C b/gcc/testsuite/g++.dg/cpp0x/pr65558.C index 5437e50..d294c95 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr65558.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr65558.C @@ -1,6 +1,7 @@ // PR c++/65558 // { dg-do compile { target c++11 } } -inline namespace __attribute__((__abi_tag__)) -{ // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" } +inline namespace +__attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" } +{ } diff --git a/gcc/testsuite/g++.dg/cpp0x/pr79369.C b/gcc/testsuite/g++.dg/cpp0x/pr79369.C new file mode 100644 index 0000000..58116f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr79369.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// PR c++/79369 accept late inline of namespace + +namespace X {} +inline namespace X {} // { dg-error "must be specified" } + +inline namespace Y {} +namespace Y {} // OK +inline namespace Y {} // also Ok -- 2.7.4