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 <[email protected]>
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]