From f60dc3caa67374c0e2941ee3866b5eaef0c6ffe6 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Tue, 4 May 2021 09:56:02 +0100 Subject: [C++20][Modules] Adjust handling of exports of namespaces and using-decls. This adjusts the handling for: export module M; export namespace {}; export namespace N {}; export using namespace N; In the first case, we were allowing empty anonymous namespaces as part of an extension allowing empty top-level entities, but that seems inappropriate in this case, since the linkage would be internal for the anonymous namespace. We now report an error for this. The second case was producing a warning diagnostic that this was accepted as an extension - however the C++20 standard does allow this as well-formed. In the third case we keep the current practice that this is accepted with a warning (as an extension). The C++20 standard says it's an error. We also ensure that using decls are only applied to items with external linkage. This adjusts error messages for exports involving redeclarations in modules to be more specific about the reason that the decl has been rejected. Differential Revision: https://reviews.llvm.org/D122119 --- clang/lib/Sema/SemaModule.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'clang/lib/Sema/SemaModule.cpp') diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 893b913..a9d3540 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -762,6 +762,7 @@ enum class UnnamedDeclKind { StaticAssert, Asm, UsingDirective, + Namespace, Context }; } @@ -791,6 +792,10 @@ unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) { // Allow exporting using-directives as an extension. return diag::ext_export_using_directive; + case UnnamedDeclKind::Namespace: + // Anonymous namespace with no content. + return diag::introduces_no_names; + case UnnamedDeclKind::Context: // Allow exporting DeclContexts that transitively contain no declarations // as an extension. @@ -818,10 +823,12 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { diagExportedUnnamedDecl(S, *UDK, D, BlockStart); // [...] shall not declare a name with internal linkage. + bool HasName = false; if (auto *ND = dyn_cast(D)) { // Don't diagnose anonymous union objects; we'll diagnose their members // instead. - if (ND->getDeclName() && ND->getFormalLinkage() == InternalLinkage) { + HasName = (bool)ND->getDeclName(); + if (HasName && ND->getFormalLinkage() == InternalLinkage) { S.Diag(ND->getLocation(), diag::err_export_internal) << ND; if (BlockStart.isValid()) S.Diag(BlockStart, diag::note_export); @@ -833,8 +840,10 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { // shall have been introduced with a name having external linkage if (auto *USD = dyn_cast(D)) { NamedDecl *Target = USD->getUnderlyingDecl(); - if (Target->getFormalLinkage() == InternalLinkage) { - S.Diag(USD->getLocation(), diag::err_export_using_internal) << Target; + Linkage Lk = Target->getFormalLinkage(); + if (Lk == InternalLinkage || Lk == ModuleLinkage) { + S.Diag(USD->getLocation(), diag::err_export_using_internal) + << (Lk == InternalLinkage ? 0 : 1) << Target; S.Diag(Target->getLocation(), diag::note_using_decl_target); if (BlockStart.isValid()) S.Diag(BlockStart, diag::note_export); @@ -842,10 +851,18 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { } // Recurse into namespace-scope DeclContexts. (Only namespace-scope - // declarations are exported.) - if (auto *DC = dyn_cast(D)) - if (DC->getRedeclContext()->isFileContext() && !isa(D)) + // declarations are exported.). + if (auto *DC = dyn_cast(D)) { + if (isa(D) && DC->decls().empty()) { + if (!HasName) + // We don't allow an empty anonymous namespace (we don't allow decls + // in them either, but that's handled in the recursion). + diagExportedUnnamedDecl(S, UnnamedDeclKind::Namespace, D, BlockStart); + else + ; // We allow an empty named namespace decl. + } else if (DC->getRedeclContext()->isFileContext() && !isa(D)) return checkExportedDeclContext(S, DC, BlockStart); + } return false; } -- cgit v1.1