On 17 September 2015 at 23:11, Jason Merrill <ja...@redhat.com> wrote: > On 09/16/2015 07:55 AM, Ville Voutilainen wrote: >> >> This is the first stab, I haven't written the tests yet. Feedback would be >> most welcome; should I put this code into a separate function? Is the >> minor >> code duplication with the regular namespace definition ok? > > > I think I'd prefer to keep it in the same function, but avoid the code > duplication.
Ok. Tested on Linux-PPC64. This patch doesn't handle attributes yet, it looks to me as if gcc doesn't support namespace attributes in the location that the standard grammar puts them into. I had to adjust a couple of point-of-declaration error/warning locations in the testsuite, but those seem reasonable to me, biased as I may be towards keeping this patch simpler than keeping those locations where they were would likely require. Nathan, this patch touches areas close to ones that your "Coding rule enforcement" patch does, please be aware of potential merge conflicts. /cp 2015-09-18 Ville Voutilainen <ville.voutilai...@gmail.com> Implement nested namespace definitions. * parser.c (cp_parser_namespace_definition): Grok nested namespace definitions. /testsuite 2015-09-18 Ville Voutilainen <ville.voutilai...@gmail.com> Implement nested namespace definitions. * g++.dg/cpp1z/nested-namespace-def.C: New. * g++.dg/lookup/name-clash5.C: Adjust. * g++.dg/lookup/name-clash6.C: Likewise.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4f424b6..9fee310 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16953,6 +16953,8 @@ cp_parser_namespace_definition (cp_parser* parser) tree identifier, attribs; bool has_visibility; bool is_inline; + cp_token* token; + int nested_definition_count = 0; cp_ensure_no_omp_declare_simd (parser); if (cp_lexer_next_token_is_keyword (parser->lexer, RID_INLINE)) @@ -16965,7 +16967,7 @@ cp_parser_namespace_definition (cp_parser* parser) is_inline = false; /* Look for the `namespace' keyword. */ - cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE); + token = cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE); /* Get the name of the namespace. We do not attempt to distinguish between an original-namespace-definition and an @@ -16979,11 +16981,32 @@ cp_parser_namespace_definition (cp_parser* parser) /* Parse any specified attributes. */ attribs = cp_parser_attributes_opt (parser); - /* Look for the `{' to start the namespace. */ - cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); /* Start the namespace. */ push_namespace (identifier); + /* Parse any nested namespace definition. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) + { + 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; + } + ++nested_definition_count; + push_namespace (identifier); + } + } + + /* Look for the `{' to validate starting the namespace. */ + cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE); + /* "inline namespace" is equivalent to a stub namespace definition followed by a strong using directive. */ if (is_inline) @@ -17007,6 +17030,10 @@ cp_parser_namespace_definition (cp_parser* parser) if (has_visibility) pop_visibility (1); + /* Finish the nested namespace definitions. */ + while (nested_definition_count--) + pop_namespace (); + /* Finish the namespace. */ pop_namespace (); /* Look for the final `}'. */ diff --git a/gcc/testsuite/g++.dg/cpp1z/nested-namespace-def.C b/gcc/testsuite/g++.dg/cpp1z/nested-namespace-def.C new file mode 100644 index 0000000..da35835 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/nested-namespace-def.C @@ -0,0 +1,14 @@ +// { dg-options "-std=c++1z" } + +namespace A::B::C +{ + struct X {}; + namespace T::U::V { struct Y {}; }; +}; + +A::B::C::X x; +A::B::C::T::U::V::Y y; + +inline namespace D::E {}; // { dg-error "cannot be inline" } + +namespace F::G:: {}; // { dg-error "nested identifier required" } diff --git a/gcc/testsuite/g++.dg/lookup/name-clash5.C b/gcc/testsuite/g++.dg/lookup/name-clash5.C index 74595c2..9673bb9 100644 --- a/gcc/testsuite/g++.dg/lookup/name-clash5.C +++ b/gcc/testsuite/g++.dg/lookup/name-clash5.C @@ -6,8 +6,8 @@ // "[Note: a namespace name or a class template name must be unique in its // declarative region (7.3.2, clause 14). ]" -namespace N -{ // { dg-message "previous declaration" } +namespace N // { dg-message "previous declaration" } +{ } class N; // { dg-error "redeclared" } diff --git a/gcc/testsuite/g++.dg/lookup/name-clash6.C b/gcc/testsuite/g++.dg/lookup/name-clash6.C index 6918142..f27e04a 100644 --- a/gcc/testsuite/g++.dg/lookup/name-clash6.C +++ b/gcc/testsuite/g++.dg/lookup/name-clash6.C @@ -8,6 +8,6 @@ class N; // { dg-message "previous declaration" } -namespace N -{ // { dg-error "redeclared" } +namespace N // { dg-error "redeclared" } +{ }