tbaeder created this revision.
tbaeder added reviewers: rsmith, aaron.ballman.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

As part of P1766R1 
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1766r1.html>, allow 
unnamed decls in `export{}` blocks.

I've adjusted the module-ts tests as well, but I am (generally) not sure 
whether code for C++20 modules should affect the modules-ts cases. What's the 
policy here?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D117295

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaModule.cpp
  clang/test/CXX/module/module.interface/p3.cpp
  clang/test/Modules/cxx20-export.cpp
  clang/test/SemaCXX/modules-ts.cppm

Index: clang/test/SemaCXX/modules-ts.cppm
===================================================================
--- clang/test/SemaCXX/modules-ts.cppm
+++ clang/test/SemaCXX/modules-ts.cppm
@@ -50,11 +50,8 @@
 import foo;
 
 export {} // expected-error {{export declaration cannot be empty}}
-export {  // expected-note {{begins here}}
-  ;       // expected-warning {{ISO C++20 does not permit an empty declaration to appear in an export block}}
-}
-export {               // expected-note {{begins here}}
-  static_assert(true); // expected-warning {{ISO C++20 does not permit a static_assert declaration to appear in an export block}}
+export {
+  static_assert(true);
 }
 
 int use_b = b;
Index: clang/test/Modules/cxx20-export.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/cxx20-export.cpp
@@ -0,0 +1,22 @@
+
+// RUN: %clang_cc1 -std=c++20 -fmodules -verify %s
+export module testmodule;
+
+export static_assert(true); // expected-error {{static_assert declaration cannot be exported}}
+
+namespace A {};
+
+export {
+#define STR(x) constexpr char x[] = #x;
+  STR(foo);
+#undef STR
+
+  static_assert(true);
+
+  template <typename T> struct X { T t; };
+  template <typename T> X(T) -> X<T>;
+
+  ; // Empty declaration
+
+  using namespace A;
+}
Index: clang/test/CXX/module/module.interface/p3.cpp
===================================================================
--- clang/test/CXX/module/module.interface/p3.cpp
+++ clang/test/CXX/module/module.interface/p3.cpp
@@ -9,12 +9,6 @@
 export static_assert(true); // expected-error {{static_assert declaration cannot be exported}}
 export using namespace A; // expected-error {{ISO C++20 does not permit using directive to be exported}}
 
-export { // expected-note 3{{export block begins here}}
-  ; // expected-error {{ISO C++20 does not permit an empty declaration to appear in an export block}}
-  static_assert(true); // expected-error {{ISO C++20 does not permit a static_assert declaration to appear in an export block}}
-  using namespace A; // expected-error {{ISO C++20 does not permit using directive to be exported}}
-}
-
 export struct {}; // expected-error {{must be class member}} expected-error {{GNU extension}} expected-error {{does not declare anything}}
 export struct {} struct_;
 export union {}; // expected-error {{must be declared 'static'}} expected-error {{does not declare anything}}
Index: clang/lib/Sema/SemaModule.cpp
===================================================================
--- clang/lib/Sema/SemaModule.cpp
+++ clang/lib/Sema/SemaModule.cpp
@@ -615,13 +615,11 @@
   return llvm::None;
 }
 
-unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) {
+static unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK) {
   switch (UDK) {
   case UnnamedDeclKind::Empty:
   case UnnamedDeclKind::StaticAssert:
-    // Allow empty-declarations and static_asserts in an export block as an
-    // extension.
-    return InBlock ? diag::ext_export_no_name_block : diag::err_export_no_name;
+    return diag::err_export_no_name;
 
   case UnnamedDeclKind::UsingDirective:
     // Allow exporting using-directives as an extension.
@@ -640,8 +638,7 @@
 
 static void diagExportedUnnamedDecl(Sema &S, UnnamedDeclKind UDK, Decl *D,
                                     SourceLocation BlockStart) {
-  S.Diag(D->getLocation(), getUnnamedDeclDiag(UDK, BlockStart.isValid()))
-      << (unsigned)UDK;
+  S.Diag(D->getLocation(), getUnnamedDeclDiag(UDK)) << (unsigned)UDK;
   if (BlockStart.isValid())
     S.Diag(BlockStart, diag::note_export);
 }
@@ -650,8 +647,10 @@
 static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
   // C++2a [module.interface]p3:
   //   An exported declaration shall declare at least one name
-  if (auto UDK = getUnnamedDeclKind(D))
-    diagExportedUnnamedDecl(S, *UDK, D, BlockStart);
+  if (!BlockStart.isValid()) {
+    if (auto UDK = getUnnamedDeclKind(D))
+      diagExportedUnnamedDecl(S, *UDK, D, BlockStart);
+  }
 
   //   [...] shall not declare a name with internal linkage.
   if (auto *ND = dyn_cast<NamedDecl>(D)) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10971,9 +10971,6 @@
 def err_export_within_anonymous_namespace : Error<
   "export declaration appears within anonymous namespace">;
 def note_anonymous_namespace : Note<"anonymous namespace begins here">;
-def ext_export_no_name_block : ExtWarn<
-  "ISO C++20 does not permit %select{an empty|a static_assert}0 declaration "
-  "to appear in an export block">, InGroup<ExportUnnamed>;
 def ext_export_no_names : ExtWarn<
   "ISO C++20 does not permit a declaration that does not introduce any names "
   "to be exported">, InGroup<ExportUnnamed>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to