From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 68020 invoked by alias); 15 May 2017 19:38:14 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 67973 invoked by uid 89); 15 May 2017 19:38:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00,FREEMAIL_FROM,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=dna, anon, (unknown) X-HELO: mail-yb0-f177.google.com Received: from mail-yb0-f177.google.com (HELO mail-yb0-f177.google.com) (209.85.213.177) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 15 May 2017 19:38:08 +0000 Received: by mail-yb0-f177.google.com with SMTP id s22so30212890ybe.3 for ; Mon, 15 May 2017 12:38:10 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:to:from:subject:message-id:date :user-agent:mime-version:content-language; bh=G0Mr0F4tQ3z2l5jda8a+p3DqlgyC+scFKaW8Ruagf+w=; b=q5h+EEiQg6VXnTz8v8bXxnLJVDDCf6uAPHNQNK0e9gMd15U49dpwFdzAyWzI+81+oT I5YbzZ+zXTh4umwnY3vhLcShu80XTyYQmjISc+Jrg2Kme+Mfvuhi4jBnDQeLxY+dQEHi 5jhiJJW2luBKfBgzkqXvIfdLmYiufVGOEGDPxS8K+Go74P69jD73qTf8VQqArqJj9y1i 9FtfRtADQUiBWpIMDXrEPPnqCn29+q5i8v3LjWg6+dtZxhkSXSsug7uyuI+Tf5f/T7NQ AbdIu57wFQ7XW9c6LimW/4V+tp54TitTcLdBXkeeWoHhHM5kZK6AXXnfrO3sG/ry7fkD YyeA== X-Gm-Message-State: AODbwcDnULRE0dYkGCz8b6+3Bmf5fKJDblKNC5/AGiQhIKFh2WiSBjk6 la/cs0RWFmZeEw== X-Received: by 10.37.197.18 with SMTP id v18mr6603428ybe.151.1494877089493; Mon, 15 May 2017 12:38:09 -0700 (PDT) Received: from ?IPv6:2620:10d:c0a3:20fb:f6d0:5ac5:64cd:f102? ([2620:10d:c091:200::7:4a1a]) by smtp.googlemail.com with ESMTPSA id v77sm6218043ywc.6.2017.05.15.12.38.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 15 May 2017 12:38:09 -0700 (PDT) To: GCC Patches From: Nathan Sidwell Subject: [C++ PATCH] push_namespace cleanup Message-ID: <5a5c09f5-1e45-8b63-bed9-7e9531519abd@acm.org> Date: Mon, 15 May 2017 19:52:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.1.0 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------01C7F2EFCB524E4A696CA650" X-SW-Source: 2017-05/txt/msg01213.txt.bz2 This is a multi-part message in MIME format. --------------01C7F2EFCB524E4A696CA650 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-length: 338 This cleanup patch from the modules branch fixes pr 79369, where we would accept inlining of an already existing namespace. I changed push_namespace to return a count of the depth pushed, because I also have a fix for DR 2061, where we can end up pushing more than one namespace. That'll be applied later. nathan -- Nathan Sidwell --------------01C7F2EFCB524E4A696CA650 Content-Type: text/x-patch; name="ns.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ns.diff" Content-length: 14498 2017-05-15 Nathan Sidwell 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. Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 248066) +++ cp/cp-tree.h (working copy) @@ -333,6 +333,7 @@ extern GTY(()) tree cp_global_trees[CPTI 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. */ Index: cp/name-lookup.c =================================================================== --- cp/name-lookup.c (revision 248066) +++ cp/name-lookup.c (working copy) @@ -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. */ Index: cp/name-lookup.h =================================================================== --- cp/name-lookup.h (revision 248066) +++ cp/name-lookup.h (working copy) @@ -340,7 +340,7 @@ extern tree pushdecl (tree, bool is_frie 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); Index: cp/parser.c =================================================================== --- cp/parser.c (revision 248066) +++ cp/parser.c (working copy) @@ -18172,114 +18172,88 @@ cp_parser_namespace_name (cp_parser* par 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; - } - - /* Start the namespace. */ - bool ok = push_namespace (identifier); - - /* 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) + identifier = NULL_TREE; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + identifier = cp_parser_identifier (parser); + + /* Parse any attributes specified after the identifier. */ + attribs = chainon (attribs, cp_parser_attributes_opt (parser)); + } + + 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. Index: testsuite/g++.dg/cpp0x/pr65558.C =================================================================== --- testsuite/g++.dg/cpp0x/pr65558.C (revision 248066) +++ testsuite/g++.dg/cpp0x/pr65558.C (working copy) @@ -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" } +{ } Index: testsuite/g++.dg/cpp0x/pr79369.C =================================================================== --- testsuite/g++.dg/cpp0x/pr79369.C (revision 0) +++ testsuite/g++.dg/cpp0x/pr79369.C (working copy) @@ -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 --------------01C7F2EFCB524E4A696CA650--