<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Mon, 12 Nov 2018 at 09:22, Erich Keane via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: erichkeane<br>
Date: Mon Nov 12 09:19:48 2018<br>
New Revision: 346677<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=346677&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=346677&view=rev</a><br>
Log:<br>
Implement P1094R2 (nested inline namespaces)<br>
<br>
As approved for the Working Paper in San Diego, support annotating<br>
inline namespaces with 'inline'.<br>
<br>
Change-Id: I51a654e11ffb475bf27cccb2458768151619e384<br>
<br>
Added:<br>
    cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp   (with props)<br>
Modified:<br>
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>
    cfe/trunk/include/clang/Parse/Parser.h<br>
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
    cfe/trunk/www/cxx_status.html<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=346677&r1=346676&r2=346677&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=346677&r1=346676&r2=346677&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Nov 12 09:19:48 2018<br>
@@ -222,6 +222,11 @@ def ext_nested_namespace_definition : Ex<br>
 def warn_cxx14_compat_nested_namespace_definition : Warning<<br>
   "nested namespace definition is incompatible with C++ standards before C++17">,<br>
   InGroup<CXXPre17Compat>, DefaultIgnore;<br>
+def ext_inline_nested_namespace_definition : ExtWarn<<br>
+  "inline nested namespace definition is a C++2a extension">, InGroup<CXX2a>;<br>
+def warn_cxx17_compat_inline_nested_namespace_definition : Warning<<br>
+  "inline nested namespace definition is incompatible with C++ standards before"<br>
+  " C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;<br>
 def err_inline_nested_namespace_definition : Error<<br>
   "nested namespace definition cannot be 'inline'">;<br>
 def err_expected_semi_after_attribute_list : Error<<br>
<br>
Modified: cfe/trunk/include/clang/Parse/Parser.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=346677&r1=346676&r2=346677&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=346677&r1=346676&r2=346677&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/Parser.h (original)<br>
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Nov 12 09:19:48 2018<br>
@@ -2659,9 +2659,16 @@ private:<br>
   DeclGroupPtrTy ParseNamespace(DeclaratorContext Context,<br>
                                 SourceLocation &DeclEnd,<br>
                                 SourceLocation InlineLoc = SourceLocation());<br>
-  void ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,<br>
-                           std::vector<IdentifierInfo *> &Ident,<br>
-                           std::vector<SourceLocation> &NamespaceLoc,<br>
+<br>
+  struct InnerNamespaceInfo {<br>
+    SourceLocation NamespaceLoc;<br>
+    SourceLocation InlineLoc;<br>
+    SourceLocation IdentLoc;<br>
+    IdentifierInfo *Ident;<br>
+  };<br>
+  using InnerNamespaceInfoList = llvm::SmallVector<InnerNamespaceInfo, 4>;<br>
+<br>
+  void ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,<br>
                            unsigned int index, SourceLocation &InlineLoc,<br>
                            ParsedAttributes &attrs,<br>
                            BalancedDelimiterTracker &Tracker);<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=346677&r1=346676&r2=346677&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=346677&r1=346676&r2=346677&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Nov 12 09:19:48 2018<br>
@@ -33,24 +33,23 @@ using namespace clang;<br>
 /// may either be a top level namespace or a block-level namespace alias. If<br>
 /// there was an inline keyword, it has already been parsed.<br>
 ///<br>
-///       namespace-definition: [C++ 7.3: basic.namespace]<br>
+///       namespace-definition: [C++: namespace.def]<br>
 ///         named-namespace-definition<br>
 ///         unnamed-namespace-definition<br>
+///         nested-namespace-definition<br>
+///<br>
+///       named-namespace-definition:<br>
+///         'inline'[opt] 'namespace' attributes[opt] identifier '{' namespace-body '}'<br>
 ///<br>
 ///       unnamed-namespace-definition:<br>
 ///         'inline'[opt] 'namespace' attributes[opt] '{' namespace-body '}'<br>
 ///<br>
-///       named-namespace-definition:<br>
-///         original-namespace-definition<br>
-///         extension-namespace-definition<br>
+///       nested-namespace-definition:<br>
+///         'namespace' enclosing-namespace-specifier '::' 'inline'[opt] identifier '{' namespace-body '}'<br>
 ///<br>
-///       original-namespace-definition:<br>
-///         'inline'[opt] 'namespace' identifier attributes[opt]<br>
-///             '{' namespace-body '}'<br>
-///<br>
-///       extension-namespace-definition:<br>
-///         'inline'[opt] 'namespace' original-namespace-name<br>
-///             '{' namespace-body '}'<br>
+///       enclosing-namespace-specifier:<br>
+///         identifier<br>
+///         enclosing-namespace-specifier '::' 'inline'[opt] identifier<br>
 ///<br>
 ///       namespace-alias-definition:  [C++ 7.3.2: namespace.alias]<br>
 ///         'namespace' identifier '=' qualified-namespace-specifier ';'<br>
@@ -70,9 +69,8 @@ Parser::DeclGroupPtrTy Parser::ParseName<br>
<br>
   SourceLocation IdentLoc;<br>
   IdentifierInfo *Ident = nullptr;<br>
-  std::vector<SourceLocation> ExtraIdentLoc;<br>
-  std::vector<IdentifierInfo*> ExtraIdent;<br>
-  std::vector<SourceLocation> ExtraNamespaceLoc;<br>
+  InnerNamespaceInfoList ExtraNSs;<br>
+  SourceLocation FirstNestedInlineLoc;<br>
<br>
   ParsedAttributesWithRange attrs(AttrFactory);<br>
   SourceLocation attrLoc;<br>
@@ -88,15 +86,29 @@ Parser::DeclGroupPtrTy Parser::ParseName<br>
   if (Tok.is(tok::identifier)) {<br>
     Ident = Tok.getIdentifierInfo();<br>
     IdentLoc = ConsumeToken();  // eat the identifier.<br>
-    while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) {<br>
-      ExtraNamespaceLoc.push_back(ConsumeToken());<br>
-      ExtraIdent.push_back(Tok.getIdentifierInfo());<br>
-      ExtraIdentLoc.push_back(ConsumeToken());<br>
+    while (Tok.is(tok::coloncolon) &&<br>
+           (NextToken().is(tok::identifier) ||<br>
+            (NextToken().is(tok::kw_inline) &&<br>
+             GetLookAheadToken(2).is(tok::identifier)))) {<br>
+<br>
+      InnerNamespaceInfo Info;<br>
+      Info.NamespaceLoc = ConsumeToken();<br>
+<br>
+      if (Tok.is(tok::kw_inline)) {<br>
+        Info.InlineLoc = ConsumeToken();<br>
+        if (FirstNestedInlineLoc.isInvalid())<br>
+          FirstNestedInlineLoc = Info.InlineLoc;<br>
+      }<br>
+<br>
+      Info.Ident = Tok.getIdentifierInfo();<br>
+      Info.IdentLoc = ConsumeToken();<br>
+<br>
+      ExtraNSs.push_back(Info);<br>
     }<br>
   }<br>
<br>
   // A nested namespace definition cannot have attributes.<br>
-  if (!ExtraNamespaceLoc.empty() && attrLoc.isValid())<br>
+  if (!ExtraNSs.empty() && attrLoc.isValid())<br>
     Diag(attrLoc, diag::err_unexpected_nested_namespace_attribute);<br>
<br>
   // Read label attributes, if present.<br>
@@ -138,13 +150,21 @@ Parser::DeclGroupPtrTy Parser::ParseName<br>
     return nullptr;<br>
   }<br>
<br>
-  if (ExtraIdent.empty()) {<br>
+  if (ExtraNSs.empty()) {<br>
     // Normal namespace definition, not a nested-namespace-definition.<br>
   } else if (InlineLoc.isValid()) {<br>
     Diag(InlineLoc, diag::err_inline_nested_namespace_definition);<br>
+  } else if (getLangOpts().CPlusPlus2a) {<br>
+    Diag(ExtraNSs[0].NamespaceLoc,<br>
+         diag::warn_cxx14_compat_nested_namespace_definition);<br>
+    if (FirstNestedInlineLoc.isValid())<br>
+      Diag(FirstNestedInlineLoc,<br>
+           diag::warn_cxx17_compat_inline_nested_namespace_definition);<br>
   } else if (getLangOpts().CPlusPlus17) {<br>
-    Diag(ExtraNamespaceLoc[0],<br>
+    Diag(ExtraNSs[0].NamespaceLoc,<br>
          diag::warn_cxx14_compat_nested_namespace_definition);<br>
+    if (FirstNestedInlineLoc.isValid())<br>
+      Diag(FirstNestedInlineLoc, diag::ext_inline_nested_namespace_definition);<br>
   } else {<br>
     TentativeParsingAction TPA(*this);<br>
     SkipUntil(tok::r_brace, StopBeforeMatch);<br>
@@ -152,26 +172,31 @@ Parser::DeclGroupPtrTy Parser::ParseName<br>
     TPA.Revert();<br>
<br>
     if (!rBraceToken.is(tok::r_brace)) {<br>
-      Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)<br>
-          << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());<br>
+      Diag(ExtraNSs[0].NamespaceLoc, diag::ext_nested_namespace_definition)<br>
+          << SourceRange(ExtraNSs.front().NamespaceLoc,<br>
+                         ExtraNSs.back().IdentLoc);<br>
     } else {<br>
       std::string NamespaceFix;<br>
-      for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(),<br>
-           E = ExtraIdent.end(); I != E; ++I) {<br>
+      for (const auto &ExtraNS : ExtraNSs) {<br>
         NamespaceFix += " { namespace ";<br></blockquote><div><br></div><div>We should include "inline" here if it was specified. (Eg,"namespace A::inline B" prior to C++17 should produce a fixit rewriting to "namespace A { inline namespace B {".)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
-        NamespaceFix += (*I)->getName();<br>
+        NamespaceFix += ExtraNS.Ident->getName();<br>
       }<br>
<br>
       std::string RBraces;<br>
-      for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)<br>
+      for (unsigned i = 0, e = ExtraNSs.size(); i != e; ++i)<br>
         RBraces +=  "} ";<br>
<br>
-      Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)<br>
-          << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),<br>
-                                                      ExtraIdentLoc.back()),<br>
-                                          NamespaceFix)<br>
+      Diag(ExtraNSs[0].NamespaceLoc, diag::ext_nested_namespace_definition)<br>
+          << FixItHint::CreateReplacement(<br>
+                 SourceRange(ExtraNSs.front().NamespaceLoc,<br>
+                             ExtraNSs.back().IdentLoc),<br>
+                 NamespaceFix)<br>
           << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces);<br>
     }<br>
+<br>
+    // Warn about nested inline namespaces.<br>
+    if (FirstNestedInlineLoc.isValid())<br>
+      Diag(FirstNestedInlineLoc, diag::ext_inline_nested_namespace_definition);<br>
   }<br>
<br>
   // If we're still good, complain about inline namespaces in non-C++0x now.<br>
@@ -192,8 +217,7 @@ Parser::DeclGroupPtrTy Parser::ParseName<br>
<br>
   // Parse the contents of the namespace.  This includes parsing recovery on<br>
   // any improperly nested namespaces.<br>
-  ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0,<br>
-                      InlineLoc, attrs, T);<br>
+  ParseInnerNamespace(ExtraNSs, 0, InlineLoc, attrs, T);<br>
<br>
   // Leave the namespace scope.<br>
   NamespaceScope.Exit();<br>
@@ -206,13 +230,11 @@ Parser::DeclGroupPtrTy Parser::ParseName<br>
 }<br>
<br>
 /// ParseInnerNamespace - Parse the contents of a namespace.<br>
-void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,<br>
-                                 std::vector<IdentifierInfo *> &Ident,<br>
-                                 std::vector<SourceLocation> &NamespaceLoc,<br>
+void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,<br>
                                  unsigned int index, SourceLocation &InlineLoc,<br>
                                  ParsedAttributes &attrs,<br>
                                  BalancedDelimiterTracker &Tracker) {<br>
-  if (index == Ident.size()) {<br>
+  if (index == InnerNSs.size()) {<br>
     while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&<br>
            Tok.isNot(tok::eof)) {<br>
       ParsedAttributesWithRange attrs(AttrFactory);<br>
@@ -233,13 +255,13 @@ void Parser::ParseInnerNamespace(std::ve<br>
   ParseScope NamespaceScope(this, Scope::DeclScope);<br>
   UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;<br>
   Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(<br>
-      getCurScope(), SourceLocation(), NamespaceLoc[index], IdentLoc[index],<br>
-      Ident[index], Tracker.getOpenLocation(), attrs,<br>
-      ImplicitUsingDirectiveDecl);<br>
+      getCurScope(), InnerNSs[index].InlineLoc, InnerNSs[index].NamespaceLoc,<br>
+      InnerNSs[index].IdentLoc, InnerNSs[index].Ident,<br>
+      Tracker.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl);<br>
   assert(!ImplicitUsingDirectiveDecl &&<br>
          "nested namespace definition cannot define anonymous namespace");<br>
<br>
-  ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,<br>
+  ParseInnerNamespace(InnerNSs, ++index, InlineLoc,<br>
                       attrs, Tracker);<br>
<br>
   NamespaceScope.Exit();<br>
<br>
Added: cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp?rev=346677&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp?rev=346677&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp (added)<br>
+++ cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp Mon Nov 12 09:19:48 2018<br>
@@ -0,0 +1,51 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14<br>
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++17<br>
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++2a -Wc++17-compat<br>
+<br>
+namespace inline foo1::foo2::foo3 { // expected-error {{expected identifier or '{'}} expected-error {{use of undeclared identifier 'foo1'}}<br>
+}<br>
+<br>
+inline namespace foo4::foo5::foo6 { // expected-error {{nested namespace definition cannot be 'inline'}}}<br>
+}<br>
+<br>
+#if __cplusplus <= 201402L<br>
+// expected-warning@+7 {{nested namespace definition is a C++17 extension; define each namespace separately}}<br>
+// expected-warning@+6 {{inline nested namespace definition is a C++2a extension}}<br>
+#elif __cplusplus <= 201703L<br>
+// expected-warning@+4 {{inline nested namespace definition is a C++2a extension}}<br>
+#else<br>
+// expected-warning@+2 {{inline nested namespace definition is incompatible with C++ standards before C++2a}}<br>
+#endif<br>
+namespace valid1::valid2::inline valid3::inline valid4::valid5{}<br>
+// expected-note@-1 2 {{previous definition is here}}<br>
+<br>
+#if __cplusplus <= 201402L<br>
+// expected-warning@+3 {{nested namespace definition is a C++17 extension; define each namespace separately}}<br>
+#endif<br>
+//expected-warning@+1 2 {{inline namespace reopened as a non-inline namespace}}<br>
+namespace valid1::valid2::valid3::valid4::valid5{}<br>
+<br>
+#if __cplusplus <= 201402L<br>
+// expected-warning@+7 {{nested namespace definition is a C++17 extension; define each namespace separately}}<br>
+// expected-warning@+6 {{inline nested namespace definition is a C++2a extension}}<br>
+#elif __cplusplus <= 201703L<br>
+// expected-warning@+4 {{inline nested namespace definition is a C++2a extension}}<br>
+#else<br>
+// expected-warning@+2 {{inline nested namespace definition is incompatible with C++ standards before C++2a}}<br>
+#endif<br>
+namespace valid1::valid2::inline valid3::inline valid4::valid5{}<br>
+// expected-note@-1 2 {{previous definition is here}}<br>
+<br>
+namespace valid1 {<br>
+  namespace valid2 {<br>
+//expected-warning@+1 {{inline namespace reopened as a non-inline namespace}}<br>
+    namespace valid3 {<br>
+//expected-warning@+1 {{inline namespace reopened as a non-inline namespace}}<br>
+      namespace valid4 {<br>
+        namespace valid5 {<br>
+        }<br>
+      }<br>
+    }<br>
+  }<br>
+}<br>
+<br>
<br>
Propchange: cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp<br>
------------------------------------------------------------------------------<br>
    svn:eol-style = native<br>
<br>
Propchange: cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp<br>
------------------------------------------------------------------------------<br>
    svn:keywords = "Author Date Id Rev URL"<br>
<br>
Propchange: cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = text/plain<br>
<br>
Modified: cfe/trunk/www/cxx_status.html<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=346677&r1=346676&r2=346677&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=346677&r1=346676&r2=346677&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/www/cxx_status.html (original)<br>
+++ cfe/trunk/www/cxx_status.html Mon Nov 12 09:19:48 2018<br>
@@ -1011,7 +1011,7 @@ as the draft C++2a standard evolves.<br>
     <tr><br>
       <td>Nested inline namespaces</td><br>
       <td><a href="<a href="http://wg21.link/p1094r2" rel="noreferrer" target="_blank">http://wg21.link/p1094r2</a>">P1094R2</a></td><br>
-      <td class="none" align="center">No</td><br>
+      <td class="svn" align="center">SVN</td><br>
     </tr><br>
 </table><br>
 </details><br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div>