[clang] bed75fa - [Clang] Reject programs declaring namespace std to be inline

Po-yao Chang via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 24 10:31:45 PDT 2023


Author: Po-yao Chang
Date: 2023-07-25T01:30:23+08:00
New Revision: bed75faf7d768f8375681db6a3fb7c3c35eeb5aa

URL: https://github.com/llvm/llvm-project/commit/bed75faf7d768f8375681db6a3fb7c3c35eeb5aa
DIFF: https://github.com/llvm/llvm-project/commit/bed75faf7d768f8375681db6a3fb7c3c35eeb5aa.diff

LOG: [Clang] Reject programs declaring namespace std to be inline

Fixes #64041

Differential Revision: https://reviews.llvm.org/D156063

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d5f179ae828f73..d6cf96bee488d1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -84,6 +84,7 @@ C++ Language Changes
   directly rather than instantiating the definition from the standard library.
 - Implemented `CWG2518 <https://wg21.link/CWG2518>`_ which allows ``static_assert(false)``
   to not be ill-formed when its condition is evaluated in the context of a template definition.
+- Declaring namespace std to be an inline namespace is now prohibited, `[namespace.std]p7`.
 
 C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fe4c3005c0ba3f..c88f25209fc0fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1579,6 +1579,8 @@ def warn_inline_namespace_reopened_noninline : Warning<
   InGroup<InlineNamespaceReopenedNoninline>;
 def err_inline_namespace_mismatch : Error<
   "non-inline namespace cannot be reopened as inline">;
+def err_inline_namespace_std : Error<
+  "cannot declare the namespace 'std' to be inline">;
 
 def err_unexpected_friend : Error<
   "friends can only be classes or functions">;

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index c59ab8b69594e5..b62f3c475c450c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -11388,6 +11388,20 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
 
   NamespaceDecl *PrevNS = nullptr;
   if (II) {
+    // C++ [namespace.std]p7:
+    //   A translation unit shall not declare namespace std to be an inline
+    //   namespace (9.8.2).
+    //
+    // Precondition: the std namespace is in the file scope and is declared to
+    // be inline
+    auto DiagnoseInlineStdNS = [&]() {
+      assert(IsInline && II->isStr("std") &&
+             CurContext->getRedeclContext()->isTranslationUnit() &&
+             "Precondition of DiagnoseInlineStdNS not met");
+      Diag(InlineLoc, diag::err_inline_namespace_std)
+          << SourceRange(InlineLoc, InlineLoc.getLocWithOffset(6));
+      IsInline = false;
+    };
     // C++ [namespace.def]p2:
     //   The identifier in an original-namespace-definition shall not
     //   have been previously defined in the declarative region in
@@ -11408,7 +11422,10 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
 
     if (PrevNS) {
       // This is an extended namespace definition.
-      if (IsInline != PrevNS->isInline())
+      if (IsInline && II->isStr("std") &&
+          CurContext->getRedeclContext()->isTranslationUnit())
+        DiagnoseInlineStdNS();
+      else if (IsInline != PrevNS->isInline())
         DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II,
                                         &IsInline, PrevNS);
     } else if (PrevDecl) {
@@ -11420,6 +11437,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
       // Continue on to push Namespc as current DeclContext and return it.
     } else if (II->isStr("std") &&
                CurContext->getRedeclContext()->isTranslationUnit()) {
+      if (IsInline)
+        DiagnoseInlineStdNS();
       // This is the first "real" definition of the namespace "std", so update
       // our cache of the "std" namespace to point at this definition.
       PrevNS = getStdNamespace();

diff  --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
index 39bed7db7ab38f..1e8df0cdd8ed79 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
 
 // FIXME: We should probably suppress the warning on reopening an inline
 // namespace without the inline keyword if it's not the first opening of the
@@ -16,3 +16,11 @@ namespace X {
   inline namespace {} // expected-note {{previous definition}}
   namespace {} // expected-warning {{inline namespace reopened as a non-inline namespace}}
 }
+
+namespace std {}
+inline namespace std {} // expected-error{{cannot declare the namespace 'std' to be inline}}
+inline namespace std::foo {} // expected-error{{cannot declare the namespace 'std' to be inline}}
+                             // expected-error at -1{{nested namespace definition cannot be 'inline'}}
+namespace foo::inline std {} // expected-note {{previous definition}}
+namespace foo { inline namespace std {} } // OK
+namespace foo { namespace std {} } // expected-warning {{inline namespace reopened as a non-inline namespace}}


        


More information about the cfe-commits mailing list