r346677 - Implement P1094R2 (nested inline namespaces)

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 12 11:59:28 PST 2018


On Mon, 12 Nov 2018 at 09:22, Erich Keane via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: erichkeane
> Date: Mon Nov 12 09:19:48 2018
> New Revision: 346677
>
> URL: http://llvm.org/viewvc/llvm-project?rev=346677&view=rev
> Log:
> Implement P1094R2 (nested inline namespaces)
>
> As approved for the Working Paper in San Diego, support annotating
> inline namespaces with 'inline'.
>
> Change-Id: I51a654e11ffb475bf27cccb2458768151619e384
>
> Added:
>     cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
>  (with props)
> Modified:
>     cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
>     cfe/trunk/include/clang/Parse/Parser.h
>     cfe/trunk/lib/Parse/ParseDeclCXX.cpp
>     cfe/trunk/www/cxx_status.html
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=346677&r1=346676&r2=346677&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Nov 12
> 09:19:48 2018
> @@ -222,6 +222,11 @@ def ext_nested_namespace_definition : Ex
>  def warn_cxx14_compat_nested_namespace_definition : Warning<
>    "nested namespace definition is incompatible with C++ standards before
> C++17">,
>    InGroup<CXXPre17Compat>, DefaultIgnore;
> +def ext_inline_nested_namespace_definition : ExtWarn<
> +  "inline nested namespace definition is a C++2a extension">,
> InGroup<CXX2a>;
> +def warn_cxx17_compat_inline_nested_namespace_definition : Warning<
> +  "inline nested namespace definition is incompatible with C++ standards
> before"
> +  " C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
>  def err_inline_nested_namespace_definition : Error<
>    "nested namespace definition cannot be 'inline'">;
>  def err_expected_semi_after_attribute_list : Error<
>
> Modified: cfe/trunk/include/clang/Parse/Parser.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=346677&r1=346676&r2=346677&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Parse/Parser.h (original)
> +++ cfe/trunk/include/clang/Parse/Parser.h Mon Nov 12 09:19:48 2018
> @@ -2659,9 +2659,16 @@ private:
>    DeclGroupPtrTy ParseNamespace(DeclaratorContext Context,
>                                  SourceLocation &DeclEnd,
>                                  SourceLocation InlineLoc =
> SourceLocation());
> -  void ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
> -                           std::vector<IdentifierInfo *> &Ident,
> -                           std::vector<SourceLocation> &NamespaceLoc,
> +
> +  struct InnerNamespaceInfo {
> +    SourceLocation NamespaceLoc;
> +    SourceLocation InlineLoc;
> +    SourceLocation IdentLoc;
> +    IdentifierInfo *Ident;
> +  };
> +  using InnerNamespaceInfoList = llvm::SmallVector<InnerNamespaceInfo, 4>;
> +
> +  void ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,
>                             unsigned int index, SourceLocation &InlineLoc,
>                             ParsedAttributes &attrs,
>                             BalancedDelimiterTracker &Tracker);
>
> Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=346677&r1=346676&r2=346677&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Nov 12 09:19:48 2018
> @@ -33,24 +33,23 @@ using namespace clang;
>  /// may either be a top level namespace or a block-level namespace alias.
> If
>  /// there was an inline keyword, it has already been parsed.
>  ///
> -///       namespace-definition: [C++ 7.3: basic.namespace]
> +///       namespace-definition: [C++: namespace.def]
>  ///         named-namespace-definition
>  ///         unnamed-namespace-definition
> +///         nested-namespace-definition
> +///
> +///       named-namespace-definition:
> +///         'inline'[opt] 'namespace' attributes[opt] identifier '{'
> namespace-body '}'
>  ///
>  ///       unnamed-namespace-definition:
>  ///         'inline'[opt] 'namespace' attributes[opt] '{' namespace-body
> '}'
>  ///
> -///       named-namespace-definition:
> -///         original-namespace-definition
> -///         extension-namespace-definition
> +///       nested-namespace-definition:
> +///         'namespace' enclosing-namespace-specifier '::' 'inline'[opt]
> identifier '{' namespace-body '}'
>  ///
> -///       original-namespace-definition:
> -///         'inline'[opt] 'namespace' identifier attributes[opt]
> -///             '{' namespace-body '}'
> -///
> -///       extension-namespace-definition:
> -///         'inline'[opt] 'namespace' original-namespace-name
> -///             '{' namespace-body '}'
> +///       enclosing-namespace-specifier:
> +///         identifier
> +///         enclosing-namespace-specifier '::' 'inline'[opt] identifier
>  ///
>  ///       namespace-alias-definition:  [C++ 7.3.2: namespace.alias]
>  ///         'namespace' identifier '=' qualified-namespace-specifier ';'
> @@ -70,9 +69,8 @@ Parser::DeclGroupPtrTy Parser::ParseName
>
>    SourceLocation IdentLoc;
>    IdentifierInfo *Ident = nullptr;
> -  std::vector<SourceLocation> ExtraIdentLoc;
> -  std::vector<IdentifierInfo*> ExtraIdent;
> -  std::vector<SourceLocation> ExtraNamespaceLoc;
> +  InnerNamespaceInfoList ExtraNSs;
> +  SourceLocation FirstNestedInlineLoc;
>
>    ParsedAttributesWithRange attrs(AttrFactory);
>    SourceLocation attrLoc;
> @@ -88,15 +86,29 @@ Parser::DeclGroupPtrTy Parser::ParseName
>    if (Tok.is(tok::identifier)) {
>      Ident = Tok.getIdentifierInfo();
>      IdentLoc = ConsumeToken();  // eat the identifier.
> -    while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) {
> -      ExtraNamespaceLoc.push_back(ConsumeToken());
> -      ExtraIdent.push_back(Tok.getIdentifierInfo());
> -      ExtraIdentLoc.push_back(ConsumeToken());
> +    while (Tok.is(tok::coloncolon) &&
> +           (NextToken().is(tok::identifier) ||
> +            (NextToken().is(tok::kw_inline) &&
> +             GetLookAheadToken(2).is(tok::identifier)))) {
> +
> +      InnerNamespaceInfo Info;
> +      Info.NamespaceLoc = ConsumeToken();
> +
> +      if (Tok.is(tok::kw_inline)) {
> +        Info.InlineLoc = ConsumeToken();
> +        if (FirstNestedInlineLoc.isInvalid())
> +          FirstNestedInlineLoc = Info.InlineLoc;
> +      }
> +
> +      Info.Ident = Tok.getIdentifierInfo();
> +      Info.IdentLoc = ConsumeToken();
> +
> +      ExtraNSs.push_back(Info);
>      }
>    }
>
>    // A nested namespace definition cannot have attributes.
> -  if (!ExtraNamespaceLoc.empty() && attrLoc.isValid())
> +  if (!ExtraNSs.empty() && attrLoc.isValid())
>      Diag(attrLoc, diag::err_unexpected_nested_namespace_attribute);
>
>    // Read label attributes, if present.
> @@ -138,13 +150,21 @@ Parser::DeclGroupPtrTy Parser::ParseName
>      return nullptr;
>    }
>
> -  if (ExtraIdent.empty()) {
> +  if (ExtraNSs.empty()) {
>      // Normal namespace definition, not a nested-namespace-definition.
>    } else if (InlineLoc.isValid()) {
>      Diag(InlineLoc, diag::err_inline_nested_namespace_definition);
> +  } else if (getLangOpts().CPlusPlus2a) {
> +    Diag(ExtraNSs[0].NamespaceLoc,
> +         diag::warn_cxx14_compat_nested_namespace_definition);
> +    if (FirstNestedInlineLoc.isValid())
> +      Diag(FirstNestedInlineLoc,
> +           diag::warn_cxx17_compat_inline_nested_namespace_definition);
>    } else if (getLangOpts().CPlusPlus17) {
> -    Diag(ExtraNamespaceLoc[0],
> +    Diag(ExtraNSs[0].NamespaceLoc,
>           diag::warn_cxx14_compat_nested_namespace_definition);
> +    if (FirstNestedInlineLoc.isValid())
> +      Diag(FirstNestedInlineLoc,
> diag::ext_inline_nested_namespace_definition);
>    } else {
>      TentativeParsingAction TPA(*this);
>      SkipUntil(tok::r_brace, StopBeforeMatch);
> @@ -152,26 +172,31 @@ Parser::DeclGroupPtrTy Parser::ParseName
>      TPA.Revert();
>
>      if (!rBraceToken.is(tok::r_brace)) {
> -      Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
> -          << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
> +      Diag(ExtraNSs[0].NamespaceLoc,
> diag::ext_nested_namespace_definition)
> +          << SourceRange(ExtraNSs.front().NamespaceLoc,
> +                         ExtraNSs.back().IdentLoc);
>      } else {
>        std::string NamespaceFix;
> -      for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(),
> -           E = ExtraIdent.end(); I != E; ++I) {
> +      for (const auto &ExtraNS : ExtraNSs) {
>          NamespaceFix += " { namespace ";
>

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 {".)


> -        NamespaceFix += (*I)->getName();
> +        NamespaceFix += ExtraNS.Ident->getName();
>        }
>
>        std::string RBraces;
> -      for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
> +      for (unsigned i = 0, e = ExtraNSs.size(); i != e; ++i)
>          RBraces +=  "} ";
>
> -      Diag(ExtraNamespaceLoc[0], diag::ext_nested_namespace_definition)
> -          <<
> FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
> -
> ExtraIdentLoc.back()),
> -                                          NamespaceFix)
> +      Diag(ExtraNSs[0].NamespaceLoc,
> diag::ext_nested_namespace_definition)
> +          << FixItHint::CreateReplacement(
> +                 SourceRange(ExtraNSs.front().NamespaceLoc,
> +                             ExtraNSs.back().IdentLoc),
> +                 NamespaceFix)
>            << FixItHint::CreateInsertion(rBraceToken.getLocation(),
> RBraces);
>      }
> +
> +    // Warn about nested inline namespaces.
> +    if (FirstNestedInlineLoc.isValid())
> +      Diag(FirstNestedInlineLoc,
> diag::ext_inline_nested_namespace_definition);
>    }
>
>    // If we're still good, complain about inline namespaces in non-C++0x
> now.
> @@ -192,8 +217,7 @@ Parser::DeclGroupPtrTy Parser::ParseName
>
>    // Parse the contents of the namespace.  This includes parsing recovery
> on
>    // any improperly nested namespaces.
> -  ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0,
> -                      InlineLoc, attrs, T);
> +  ParseInnerNamespace(ExtraNSs, 0, InlineLoc, attrs, T);
>
>    // Leave the namespace scope.
>    NamespaceScope.Exit();
> @@ -206,13 +230,11 @@ Parser::DeclGroupPtrTy Parser::ParseName
>  }
>
>  /// ParseInnerNamespace - Parse the contents of a namespace.
> -void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
> -                                 std::vector<IdentifierInfo *> &Ident,
> -                                 std::vector<SourceLocation>
> &NamespaceLoc,
> +void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,
>                                   unsigned int index, SourceLocation
> &InlineLoc,
>                                   ParsedAttributes &attrs,
>                                   BalancedDelimiterTracker &Tracker) {
> -  if (index == Ident.size()) {
> +  if (index == InnerNSs.size()) {
>      while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
>             Tok.isNot(tok::eof)) {
>        ParsedAttributesWithRange attrs(AttrFactory);
> @@ -233,13 +255,13 @@ void Parser::ParseInnerNamespace(std::ve
>    ParseScope NamespaceScope(this, Scope::DeclScope);
>    UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
>    Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
> -      getCurScope(), SourceLocation(), NamespaceLoc[index],
> IdentLoc[index],
> -      Ident[index], Tracker.getOpenLocation(), attrs,
> -      ImplicitUsingDirectiveDecl);
> +      getCurScope(), InnerNSs[index].InlineLoc,
> InnerNSs[index].NamespaceLoc,
> +      InnerNSs[index].IdentLoc, InnerNSs[index].Ident,
> +      Tracker.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl);
>    assert(!ImplicitUsingDirectiveDecl &&
>           "nested namespace definition cannot define anonymous namespace");
>
> -  ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,
> +  ParseInnerNamespace(InnerNSs, ++index, InlineLoc,
>                        attrs, Tracker);
>
>    NamespaceScope.Exit();
>
> Added: cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp?rev=346677&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
> (added)
> +++ cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp Mon
> Nov 12 09:19:48 2018
> @@ -0,0 +1,51 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
> +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++17
> +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++2a -Wc++17-compat
> +
> +namespace inline foo1::foo2::foo3 { // expected-error {{expected
> identifier or '{'}} expected-error {{use of undeclared identifier 'foo1'}}
> +}
> +
> +inline namespace foo4::foo5::foo6 { // expected-error {{nested namespace
> definition cannot be 'inline'}}}
> +}
> +
> +#if __cplusplus <= 201402L
> +// expected-warning at +7 {{nested namespace definition is a C++17
> extension; define each namespace separately}}
> +// expected-warning at +6 {{inline nested namespace definition is a C++2a
> extension}}
> +#elif __cplusplus <= 201703L
> +// expected-warning at +4 {{inline nested namespace definition is a C++2a
> extension}}
> +#else
> +// expected-warning at +2 {{inline nested namespace definition is
> incompatible with C++ standards before C++2a}}
> +#endif
> +namespace valid1::valid2::inline valid3::inline valid4::valid5{}
> +// expected-note at -1 2 {{previous definition is here}}
> +
> +#if __cplusplus <= 201402L
> +// expected-warning at +3 {{nested namespace definition is a C++17
> extension; define each namespace separately}}
> +#endif
> +//expected-warning at +1 2 {{inline namespace reopened as a non-inline
> namespace}}
> +namespace valid1::valid2::valid3::valid4::valid5{}
> +
> +#if __cplusplus <= 201402L
> +// expected-warning at +7 {{nested namespace definition is a C++17
> extension; define each namespace separately}}
> +// expected-warning at +6 {{inline nested namespace definition is a C++2a
> extension}}
> +#elif __cplusplus <= 201703L
> +// expected-warning at +4 {{inline nested namespace definition is a C++2a
> extension}}
> +#else
> +// expected-warning at +2 {{inline nested namespace definition is
> incompatible with C++ standards before C++2a}}
> +#endif
> +namespace valid1::valid2::inline valid3::inline valid4::valid5{}
> +// expected-note at -1 2 {{previous definition is here}}
> +
> +namespace valid1 {
> +  namespace valid2 {
> +//expected-warning at +1 {{inline namespace reopened as a non-inline
> namespace}}
> +    namespace valid3 {
> +//expected-warning at +1 {{inline namespace reopened as a non-inline
> namespace}}
> +      namespace valid4 {
> +        namespace valid5 {
> +        }
> +      }
> +    }
> +  }
> +}
> +
>
> Propchange:
> cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
>
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Propchange:
> cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
>
> ------------------------------------------------------------------------------
>     svn:keywords = "Author Date Id Rev URL"
>
> Propchange:
> cfe/trunk/test/Parser/cxx2a-inline-nested-namespace-definition.cpp
>
> ------------------------------------------------------------------------------
>     svn:mime-type = text/plain
>
> Modified: cfe/trunk/www/cxx_status.html
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=346677&r1=346676&r2=346677&view=diff
>
> ==============================================================================
> --- cfe/trunk/www/cxx_status.html (original)
> +++ cfe/trunk/www/cxx_status.html Mon Nov 12 09:19:48 2018
> @@ -1011,7 +1011,7 @@ as the draft C++2a standard evolves.
>      <tr>
>        <td>Nested inline namespaces</td>
>        <td><a href="http://wg21.link/p1094r2">P1094R2</a></td>
> -      <td class="none" align="center">No</td>
> +      <td class="svn" align="center">SVN</td>
>      </tr>
>  </table>
>  </details>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20181112/2b6fd603/attachment-0001.html>


More information about the cfe-commits mailing list