Index: clang/lib/Sema/SemaModule.cpp =================================================================== --- clang/lib/Sema/SemaModule.cpp +++ clang/lib/Sema/SemaModule.cpp @@ -615,12 +615,10 @@ return llvm::None; } -unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) { +static unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) { 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; case UnnamedDeclKind::UsingDirective: @@ -648,10 +646,19 @@ /// Check that it's valid to export \p D. 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 (auto UDK = getUnnamedDeclKind(D)) { + if (S.getLangOpts().CPlusPlus2b) { + // P1766R1 allows unnamed declarations in export{} blocks, but not in + // the single-declaration form of export. + // FIXME: Cite the standard once P1766R1 is reflected in the wording + if (BlockStart.isInvalid()) + diagExportedUnnamedDecl(S, *UDK, D, BlockStart); + } else { + // C++2a [module.interface]p3: + // An exported declaration shall declare at least one name + diagExportedUnnamedDecl(S, *UDK, D, BlockStart); + } + } // [...] shall not declare a name with internal linkage. if (auto *ND = dyn_cast(D)) { Index: clang/test/Modules/cxx20-export.cpp =================================================================== --- /dev/null +++ clang/test/Modules/cxx20-export.cpp @@ -0,0 +1,23 @@ + +// RUN: %clang_cc1 -std=c++2b -verify %s +export module testmodule; + +export static_assert(true); // expected-error {{static_assert declaration cannot be exported}} +export; // expected-error {{empty declaration cannot be exported}} + +namespace A {}; + +export { +#define STR(x) constexpr char x[] = #x; + STR(foo); +#undef STR + + static_assert(true); + + template struct X { T t; }; + template X(T) -> X; + + ; // Empty declaration + + using namespace A; +}