[clang] [clang][Modules] Complete the implementation of P2615: Meaningful exports (PR #194201)

Victor Chernyakin via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 27 22:49:43 PDT 2026


================
@@ -440,6 +443,87 @@ Decl *Parser::ParseExportDeclaration() {
                                        T.getCloseLocation());
 }
 
+void Parser::CheckUnbracedLinkageOrExportDeclaration(
+    Decl *LinkageOrExportDecl) {
+  const auto *DC = cast<DeclContext>(LinkageOrExportDecl);
+  if (DC->decls_empty())
+    return;
+
+  const Decl *D = *DC->decls_begin();
+
+  // Nested export declarations are diagnosed elsewhere.
+  if (isa<LinkageSpecDecl>(LinkageOrExportDecl) && isa<ExportDecl>(D)) {
+    Diag(LinkageOrExportDecl->getLocation(),
+         diag::err_invalid_decl_in_linkage_spec)
+        << 2;
+    return;
+  }
+
+  // [module.interface]/1 says:
+  //
+  //     The name-declaration of an export-declaration shall not declare a
+  //     partial specialization.
+  //
+  // There's no equivalent wording for linkage-specification.
+  if (isa<ClassTemplatePartialSpecializationDecl,
+          VarTemplatePartialSpecializationDecl>(D) &&
+      isa<LinkageSpecDecl>(LinkageOrExportDecl))
+    return;
+
+  TemplateSpecializationKind TSK = [&] {
+    if (const auto *EID = dyn_cast<ExplicitInstantiationDecl>(D))
+      return EID->getTemplateSpecializationKind();
+    if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
+      return CTSD->getTemplateSpecializationKind();
+    if (const auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
+      return VTSD->getTemplateSpecializationKind();
+    if (const auto *FD = dyn_cast<FunctionDecl>(D))
+      return FD->getTemplateSpecializationKind();
+    return TSK_Undeclared;
+  }();
+
+  if (TSK == TSK_Undeclared)
+    return;
+
+  if (const auto *ED = dyn_cast<ExportDecl>(LinkageOrExportDecl)) {
+    Diag(ED->getExportLoc(), diag::err_meaningless_export)
+        << (TSK == TSK_ExplicitSpecialization)
+        << FixItHint::CreateRemoval(ED->getExportLoc());
+    Diag(ED->getExportLoc(), diag::note_meaningless_export_explanation);
+    return;
+  }
+
+  if (const auto *LS = dyn_cast<LinkageSpecDecl>(LinkageOrExportDecl)) {
+    // HACK: Old versions of the MSVC STL used to have linkage specifications
+    // on some template specializations, but it would be too disruptive to
+    // reject them. This was fixed in
+    // https://github.com/microsoft/STL/pull/6074, merged on 2026-02-11.
+    bool IsStandardLibrarySymbolInOldMSVCSTL = [&] {
----------------
localspook wrote:

Extended the existing mechanism (required a bit of refactoring). PTAL.

https://github.com/llvm/llvm-project/pull/194201


More information about the cfe-commits mailing list