Hi all, would be nice to have nested namespace definitions in gcc. I'm not sure if this if it's possible to merge stuff like this at this stage.
2015-2-13 Andrea Azzarone <azzaro...@gmail.com> PR c++/65047 * gcc/cp/cp-tree.h Declare maybe_warn_cpp1z. * gcc/cp/error.c Define maybe_warn_cpp1z. * gcc/cp/parser.c (cp_parser_namespace_definition) Add support for nested namespace definitions. I did a full boostrap + full make check. Thanks. -- Andrea Azzarone
Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 220454) +++ gcc/cp/cp-tree.h (working copy) @@ -467,6 +467,13 @@ typedef enum cpp0x_warn_str CPP0X_REF_QUALIFIER } cpp0x_warn_str; +/* The various kinds of C++1z warnings we ecounter. */ +typedef enum cpp1z_warn_str +{ + /* nested namespace definitions. */ + CPP1Z_NESTED_NAMESPACE_DEFINITIONS +} cpp1z_warn_str; + /* The various kinds of operation used by composite_pointer_type. */ typedef enum composite_pointer_operation @@ -5518,6 +5525,7 @@ extern const char *language_to_string ( extern const char *class_key_or_enum_as_string (tree); extern void maybe_warn_variadic_templates (void); extern void maybe_warn_cpp0x (cpp0x_warn_str str); +extern void maybe_warn_cpp1z (cpp1z_warn_str str); extern bool pedwarn_cxx98 (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern location_t location_of (tree); extern void qualified_name_lookup_error (tree, tree, tree, Index: gcc/cp/error.c =================================================================== --- gcc/cp/error.c (revision 220454) +++ gcc/cp/error.c (working copy) @@ -3611,6 +3611,24 @@ maybe_warn_cpp0x (cpp0x_warn_str str) } } +void +maybe_warn_cpp1z (cpp1z_warn_str str) +{ + if (cxx_dialect >= cxx1z) + return; + + switch (str) + { + case CPP1Z_NESTED_NAMESPACE_DEFINITIONS: + pedwarn (input_location, 0, + "nested namespace definitions " + "only available with -std=c++1z or -std=gnu=c++1z"); + break; + default: + gcc_unreachable (); + } +} + /* Warn about the use of variadic templates when appropriate. */ void maybe_warn_variadic_templates (void) Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 220454) +++ gcc/cp/parser.c (working copy) @@ -16169,6 +16169,7 @@ cp_parser_namespace_name (cp_parser* par namespace-definition: named-namespace-definition unnamed-namespace-definition + nested-namespace-definition named-namespace-definition: original-namespace-definition @@ -16181,24 +16182,32 @@ cp_parser_namespace_name (cp_parser* par namespace original-namespace-name { namespace-body } unnamed-namespace-definition: - namespace { namespace-body } */ + namespace { namespace-body } + + nested-namespace-definition: + namespace enclosing-namespace-specifier :: identifier { namespace-body } + + enclosing-namespace-specifier: + identifier + enclosing-namespace-specifier :: identifier */ static void cp_parser_namespace_definition (cp_parser* parser) { + vec<tree, va_heap> extra_identifiers; tree identifier, attribs; bool has_visibility; - bool is_inline; + location_t inline_location; + unsigned ns_deepness; cp_ensure_no_omp_declare_simd (parser); if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE)) { maybe_warn_cpp0x (CPP0X_INLINE_NAMESPACES); - is_inline = true; - cp_lexer_consume_token (parser->lexer); + inline_location = cp_lexer_consume_token (parser->lexer)->location; } else - is_inline = false; + inline_location = UNKNOWN_LOCATION; /* Look for the `namespace' keyword. */ cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE); @@ -16207,22 +16216,64 @@ cp_parser_namespace_definition (cp_parse between an original-namespace-definition and an extension-namespace-definition at this point. The semantic analysis routines are responsible for that. */ + extra_identifiers.create(0); if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) - identifier = cp_parser_identifier (parser); + { + /* named-namespace-definition. */ + identifier = cp_parser_identifier (parser); + + while (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME) + { + /* nested-namespace-definition */ + cp_lexer_consume_token (parser->lexer); + extra_identifiers.safe_insert (0, cp_parser_identifier (parser)); + } + } else - identifier = NULL_TREE; + { + /* unnamed-namespace-definition. */ + identifier = NULL_TREE; + } + + if (!extra_identifiers.is_empty ()) + maybe_warn_cpp1z (CPP1Z_NESTED_NAMESPACE_DEFINITIONS); + + /* Nested namespace definitions cannot be inline. */ + if (inline_location && !extra_identifiers.is_empty ()) + { + error_at (inline_location, "nested namespace definition cannot be %<inline%>"); + extra_identifiers.release (); + cp_parser_skip_to_end_of_block_or_statement (parser); + return; + } /* Parse any specified attributes. */ attribs = cp_parser_attributes_opt (parser); + /* Attributes cannot be specified on a nested namespace definition. */ + if (attribs && !extra_identifiers.is_empty ()) + { + error_at (location_of (attribs), "attributes cannot be specified on a nested namespace definition"); + extra_identifiers.release (); + cp_parser_skip_to_end_of_block_or_statement (parser); + return; + } + /* Look for the `{' to start the namespace. */ - cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); + if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) + { + cp_parser_skip_to_end_of_block_or_statement (parser); + extra_identifiers.release (); + return; + } + /* Start the namespace. */ push_namespace (identifier); /* "inline namespace" is equivalent to a stub namespace definition followed by a strong using directive. */ - if (is_inline) + if (inline_location) { tree name_space = current_namespace; /* Set up namespace association. */ @@ -16237,6 +16288,10 @@ cp_parser_namespace_definition (cp_parse has_visibility = handle_namespace_attrs (current_namespace, attribs); + ns_deepness = extra_identifiers.length () + 1; + while (extra_identifiers.length ()) + push_namespace (extra_identifiers.pop ()); + /* Parse the body of the namespace. */ cp_parser_namespace_body (parser); @@ -16244,9 +16299,12 @@ cp_parser_namespace_definition (cp_parse pop_visibility (1); /* Finish the namespace. */ - pop_namespace (); + while (ns_deepness--) + pop_namespace (); + /* Look for the final `}'. */ cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); + extra_identifiers.release (); } /* Parse a namespace-body. Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition1.C =================================================================== --- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition1.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition1.C (working copy) @@ -0,0 +1,13 @@ +// { dg-do run } +// { dg-options "-fpermissive" } + +#include <cassert> + +namespace A::B::C { // { dg-warning "nested namespace definitions only available with" "" { target { ! c++1z } } } + int var; +} + +int main () { + A::B::C::var = 10; + assert (A::B::C::var == 10); +} Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition2.C =================================================================== --- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition2.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition2.C (working copy) @@ -0,0 +1,11 @@ +// { dg-do compile } +// { dg-options "-fpermissive" } +// { dg-prune-output "nested namespace definitions only available with" } + +inline namespace A::B::C { // { dg-error "nested namespace definition cannot be | inline" } + int var; +} + +int main () { + A::B::C::var = 10; // { dg-error "has not been declared" } +} Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition3.C =================================================================== --- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition3.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition3.C (working copy) @@ -0,0 +1,11 @@ +// { dg-do compile } +// { dg-options "-fpermissive" } +// { dg-prune-output "nested namespace definitions only available with" } + +namespace A::B::C __attribute__((visibility("hidden"))) { // { dg-error "attributes cannot be specified on a nested namespace definition" } + int var; +} + +int main () { + A::B::C::var = 10; // { dg-error "has not been declared" } +} Index: gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition4.C =================================================================== --- gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition4.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1z/nested-namespace-definition4.C (working copy) @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-fpermissive" } +// { dg-prune-output "nested namespace definitions only available with" } + +namespace A:B { // { dg-error "expected '\{' before ':' token" } + int var1; +} + +namespace A::B:C { // { dg-error "expected '\{' before ':' token" } + int var2; +} + +int main () { + A::B::var1 = 0; // { dg-error "has not been declared" } + A::B::C::var2 = 0; // { dg-error "has not been declared" } +} Index: gcc/testsuite/lib/g++-dg.exp =================================================================== --- gcc/testsuite/lib/g++-dg.exp (revision 220454) +++ gcc/testsuite/lib/g++-dg.exp (working copy) @@ -43,9 +43,9 @@ proc g++-dg-runtest { testcases flags de # if there's a dg-options line. if ![search_for $test "-std=*++"] { if [search_for $test "dg-options"] { - set option_list { -std=gnu++98 -std=gnu++11 -std=gnu++14 } + set option_list { -std=gnu++98 -std=gnu++11 -std=gnu++14 -std=gnu++17} } else { - set option_list { -std=c++98 -std=c++11 -std=c++14 } + set option_list { -std=c++98 -std=c++11 -std=c++14 -std=c++17} } } else { set option_list { "" } Index: gcc/testsuite/lib/target-supports.exp =================================================================== --- gcc/testsuite/lib/target-supports.exp (revision 220454) +++ gcc/testsuite/lib/target-supports.exp (working copy) @@ -5827,7 +5827,7 @@ proc check_effective_target_c++ { } { } # Check whether the current active language standard supports the features -# of C++11/C++14 by checking for the presence of one of the -std +# of C++11/C++14/C++17 by checking for the presence of one of the -std # flags. This assumes that the default for the compiler is C++98, and that # there will never be multiple -std= arguments on the command line. proc check_effective_target_c++11_only { } { @@ -5880,7 +5880,7 @@ proc check_effective_target_c++1z_only { if ![check_effective_target_c++] { return 0 } - return [check-flags { { } { } { -std=c++1z -std=gnu++1z } }] + return [check-flags { { } { } { -std=c++1z -std=gnu++1z -std=c++17 -std=gnu++17} }] } proc check_effective_target_c++1z { } { return [check_effective_target_c++1z_only]