diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index b45b53e..c396735 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2015-09-20  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+	Complete the implementation of N4230, Nested namespace definition.
+	* c-cppbuiltin.c: Add __cpp_namespace_attributes and
+	__cpp_nested_namespace_definitions.
+
 2015-09-18  Manuel López-Ibáñez  <manu@gcc.gnu.org>
 
 	* c-pragma.c (handle_pragma_diagnostic): Fix wrong return.
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 0e45a57..b222a9f 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -870,6 +870,8 @@ c_cpp_builtins (cpp_reader *pfile)
 	{
 	  /* Set feature test macros for C++1z.  */
 	  cpp_define (pfile, "__cpp_static_assert=201411");
+	  cpp_define (pfile, "__cpp_namespace_attributes=201411");
+	  cpp_define (pfile, "__cpp_nested_namespace_definitions=201411");
 	}
       if (flag_concepts)
 	/* Use a value smaller than the 201507 specified in
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index ab71f92..ed782a6 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2015-09-20  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+	Complete the implementation of N4230, Nested namespace definition.
+	* parser.c (cp_parser_namespace_definition): Support namespace
+	attributes both before and after the namespace identifier.
+
 2015-09-19  Trevor Saunders  <tbsaunde@tbsaunde.org>
 
 	* cp-gimplify.c (gimplify_must_not_throw_expr): Adjust.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2071276..0134189 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11645,6 +11645,9 @@ cp_parser_declaration (cp_parser* parser)
 	       (token2.type == CPP_NAME
 		&& (cp_lexer_peek_nth_token (parser->lexer, 3)->type
 		    != CPP_EQ))
+               || (token2.type == CPP_OPEN_SQUARE
+                   && cp_lexer_peek_nth_token (parser->lexer, 3)->type
+                   == CPP_OPEN_SQUARE)
 	       /* An unnamed namespace definition.  */
 	       || token2.type == CPP_OPEN_BRACE
 	       || token2.keyword == RID_ATTRIBUTE))
@@ -16969,6 +16972,9 @@ cp_parser_namespace_definition (cp_parser* parser)
   /* Look for the `namespace' keyword.  */
   token = cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
 
+  /* Parse any specified attributes before the identifier.  */
+  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
@@ -16978,8 +16984,15 @@ cp_parser_namespace_definition (cp_parser* parser)
   else
     identifier = NULL_TREE;
 
-  /* Parse any specified attributes.  */
-  attribs = cp_parser_attributes_opt (parser);
+  /* Parse any specified attributes after the identifier.  */
+  tree post_ident_attribs = cp_parser_attributes_opt (parser);
+  if (post_ident_attribs)
+    {
+      if (attribs)
+        attribs = chainon (attribs, post_ident_attribs);
+      else
+        attribs = post_ident_attribs;
+    }
 
   /* Start the namespace.  */
   push_namespace (identifier);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5fd91c1..10747a9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2015-09-20  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+	Complete the implementation of N4230, Nested namespace definition.
+	* g++.dg/cpp1y/feat-cxx11-neg.C: Add tests for C++17 namespace
+	attributes and nested namespace definitions.
+	* g++.dg/cpp1y/feat-cxx98-neg.C: Likewise.
+	* g++.dg/cpp1z/feat-cxx1z.C: Likewise.
+	* g++.dg/cpp1y/feat-cxx14-neg.C: New.
+	* g++.dg/cpp1z/namespace-attribs.C: Likewise.
+	* g++.dg/cpp1z/nested-namespace-def1.C: Add tests for attributes
+	appearing before the namespace identifier.
+
 2015-09-20  Oleg Endo  <olegendo@gcc.gnu.org>
 
 	* gcc.target/sh/pr43417.c: Move target independent test to ...
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C
index 81daa04..825d088 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11-neg.C
@@ -38,6 +38,17 @@
 #  error "__cpp_sized_deallocation" // { dg-error "error" }
 #endif
 
+// C++17 features:
+
+#ifndef __cpp_namespace_attributes
+#  error "__cpp_namespace_attributes" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_nested_namespace_definitions
+#  error "__cpp_nested_namespace_definitions" // { dg-error "error" }
+#endif
+
+
 //  Array TS features:
 
 #ifndef __cpp_runtime_arrays
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx14-neg.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx14-neg.C
new file mode 100644
index 0000000..221bd3f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx14-neg.C
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++14 } }
+
+// C++17 features:
+
+#ifndef __cpp_namespace_attributes
+#  error "__cpp_namespace_attributes" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_nested_namespace_definitions
+#  error "__cpp_nested_namespace_definitions" // { dg-error "error" }
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C
index 9c25fc3..886b3d3 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx98-neg.C
@@ -113,6 +113,16 @@
 #  error "__cpp_sized_deallocation" // { dg-error "error" }
 #endif
 
+// C++17 features:
+
+#ifndef __cpp_namespace_attributes
+#  error "__cpp_namespace_attributes" // { dg-error "error" }
+#endif
+
+#ifndef __cpp_nested_namespace_definitions
+#  error "__cpp_nested_namespace_definitions" // { dg-error "error" }
+#endif
+
 //  C++11 attributes:
 
 #ifdef __has_cpp_attribute
diff --git a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
index b3e742c..ead1665 100644
--- a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
+++ b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
@@ -6,3 +6,15 @@
 #elif __cpp_static_assert != 201411
 #  error "__cpp_static_assert != 201411"
 #endif
+
+#ifndef __cpp_namespace_attributes
+#  error "__cpp_namespace_attributes"
+#elif __cpp_namespace_attributes != 201411
+#  error "__cpp_namespace_attributes != 201411"
+#endif
+
+#ifndef __cpp_nested_namespace_definitions
+#  error "__cpp_nested_namespace_definitions"
+#elif __cpp_nested_namespace_definitions != 201411
+#  error "__cpp_nested_namespace_definitions != 201411"
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp1z/namespace-attribs.C b/gcc/testsuite/g++.dg/cpp1z/namespace-attribs.C
new file mode 100644
index 0000000..7dc2173
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/namespace-attribs.C
@@ -0,0 +1,10 @@
+// { dg-options "-std=c++1z" }
+
+namespace A __attribute ((visibility ("default"))) {}
+
+namespace B [[deprecated]] {} // { dg-warning "ignored" }
+
+namespace __attribute ((visibility ("default"))) C {}
+
+namespace [[deprecated]] D {} // { dg-warning "ignored" }
+
diff --git a/gcc/testsuite/g++.dg/cpp1z/nested-namespace-def1.C b/gcc/testsuite/g++.dg/cpp1z/nested-namespace-def1.C
index ebdb70b..3980174 100644
--- a/gcc/testsuite/g++.dg/cpp1z/nested-namespace-def1.C
+++ b/gcc/testsuite/g++.dg/cpp1z/nested-namespace-def1.C
@@ -17,3 +17,7 @@ namespace G __attribute ((visibility ("default"))) ::H {} // { dg-error "cannot
 
 namespace H [[deprecated]] ::I {} // { dg-error "cannot have attributes|ignored" }
 
+namespace __attribute ((visibility ("default"))) I::J {} // { dg-error "cannot have attributes" }
+
+namespace [[deprecated]] J::K {} // { dg-error "cannot have attributes|ignored" }
+
