From: Erich Keane Date: Mon, 12 Nov 2018 17:19:48 +0000 (+0000) Subject: Implement P1094R2 (nested inline namespaces) X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8e8c9f7c8a9e74c7007e3d71e308b4abe231712e;p=clang Implement P1094R2 (nested inline namespaces) As approved for the Working Paper in San Diego, support annotating inline namespaces with 'inline'. Change-Id: I51a654e11ffb475bf27cccb2458768151619e384 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@346677 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index f47d88a82a..d1d601ce24 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -222,6 +222,11 @@ def ext_nested_namespace_definition : ExtWarn< def warn_cxx14_compat_nested_namespace_definition : Warning< "nested namespace definition is incompatible with C++ standards before C++17">, InGroup, DefaultIgnore; +def ext_inline_nested_namespace_definition : ExtWarn< + "inline nested namespace definition is a C++2a extension">, InGroup; +def warn_cxx17_compat_inline_nested_namespace_definition : Warning< + "inline nested namespace definition is incompatible with C++ standards before" + " C++2a">, InGroup, DefaultIgnore; def err_inline_nested_namespace_definition : Error< "nested namespace definition cannot be 'inline'">; def err_expected_semi_after_attribute_list : Error< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e2a40b24c2..c643093f6e 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2659,9 +2659,16 @@ private: DeclGroupPtrTy ParseNamespace(DeclaratorContext Context, SourceLocation &DeclEnd, SourceLocation InlineLoc = SourceLocation()); - void ParseInnerNamespace(std::vector &IdentLoc, - std::vector &Ident, - std::vector &NamespaceLoc, + + struct InnerNamespaceInfo { + SourceLocation NamespaceLoc; + SourceLocation InlineLoc; + SourceLocation IdentLoc; + IdentifierInfo *Ident; + }; + using InnerNamespaceInfoList = llvm::SmallVector; + + void ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs, unsigned int index, SourceLocation &InlineLoc, ParsedAttributes &attrs, BalancedDelimiterTracker &Tracker); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c814775c77..85c972f410 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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::ParseNamespace(DeclaratorContext Context, SourceLocation IdentLoc; IdentifierInfo *Ident = nullptr; - std::vector ExtraIdentLoc; - std::vector ExtraIdent; - std::vector ExtraNamespaceLoc; + InnerNamespaceInfoList ExtraNSs; + SourceLocation FirstNestedInlineLoc; ParsedAttributesWithRange attrs(AttrFactory); SourceLocation attrLoc; @@ -88,15 +86,29 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context, 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::ParseNamespace(DeclaratorContext Context, 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::ParseNamespace(DeclaratorContext Context, 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::iterator I = ExtraIdent.begin(), - E = ExtraIdent.end(); I != E; ++I) { + for (const auto &ExtraNS : ExtraNSs) { NamespaceFix += " { namespace "; - 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::ParseNamespace(DeclaratorContext Context, // 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::ParseNamespace(DeclaratorContext Context, } /// ParseInnerNamespace - Parse the contents of a namespace. -void Parser::ParseInnerNamespace(std::vector &IdentLoc, - std::vector &Ident, - std::vector &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::vector &IdentLoc, 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(); diff --git a/test/Parser/cxx2a-inline-nested-namespace-definition.cpp b/test/Parser/cxx2a-inline-nested-namespace-definition.cpp new file mode 100644 index 0000000000..8e603d24c0 --- /dev/null +++ b/test/Parser/cxx2a-inline-nested-namespace-definition.cpp @@ -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@+7 {{nested namespace definition is a C++17 extension; define each namespace separately}} +// expected-warning@+6 {{inline nested namespace definition is a C++2a extension}} +#elif __cplusplus <= 201703L +// expected-warning@+4 {{inline nested namespace definition is a C++2a extension}} +#else +// expected-warning@+2 {{inline nested namespace definition is incompatible with C++ standards before C++2a}} +#endif +namespace valid1::valid2::inline valid3::inline valid4::valid5{} +// expected-note@-1 2 {{previous definition is here}} + +#if __cplusplus <= 201402L +// expected-warning@+3 {{nested namespace definition is a C++17 extension; define each namespace separately}} +#endif +//expected-warning@+1 2 {{inline namespace reopened as a non-inline namespace}} +namespace valid1::valid2::valid3::valid4::valid5{} + +#if __cplusplus <= 201402L +// expected-warning@+7 {{nested namespace definition is a C++17 extension; define each namespace separately}} +// expected-warning@+6 {{inline nested namespace definition is a C++2a extension}} +#elif __cplusplus <= 201703L +// expected-warning@+4 {{inline nested namespace definition is a C++2a extension}} +#else +// expected-warning@+2 {{inline nested namespace definition is incompatible with C++ standards before C++2a}} +#endif +namespace valid1::valid2::inline valid3::inline valid4::valid5{} +// expected-note@-1 2 {{previous definition is here}} + +namespace valid1 { + namespace valid2 { +//expected-warning@+1 {{inline namespace reopened as a non-inline namespace}} + namespace valid3 { +//expected-warning@+1 {{inline namespace reopened as a non-inline namespace}} + namespace valid4 { + namespace valid5 { + } + } + } + } +} + diff --git a/www/cxx_status.html b/www/cxx_status.html index f7db88f649..ee0c6e8542 100755 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -1011,7 +1011,7 @@ as the draft C++2a standard evolves. Nested inline namespaces P1094R2 - No + SVN