[clang] [clang] Don't dllexport inherited constructors with -fno-dllexport-inlines (PR #187684)

Hans Wennborg via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 20 05:06:48 PDT 2026


https://github.com/zmodem created https://github.com/llvm/llvm-project/pull/187684

The inherited constructors are inline thunks, so like other inline functions they are exempted from ABI compatibility concerns with this flag, and should not be exported.

This is a follow-up to #182706

>From 3f01cc72125cbef52824e4e7e9b2c915dfc4dc77 Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at chromium.org>
Date: Fri, 20 Mar 2026 12:35:58 +0100
Subject: [PATCH] [clang] Don't dllexport inherited constructors with
 -fno-dllexport-inlines

The inherited constructors are inline thunks, so like other inline
functions they are exempted from ABI compatibility concerns with this
flag, and should not be exported.

This is a follow-up to #182706
---
 clang/lib/Sema/SemaDeclCXX.cpp                | 11 +++------
 .../CodeGenCXX/dllexport-inherited-ctor.cpp   | 24 +++++++++----------
 .../dllexport-constrained-inherited-ctor.cpp  |  1 +
 3 files changed, 15 insertions(+), 21 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 2a24ee42bcb4d..87e07c8ac0d05 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6590,7 +6590,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
 
   // Inherited constructors are created lazily; force their creation now so the
   // loop below can propagate the DLL attribute to them.
-  if (ClassExported) {
+  if (ClassExported && getLangOpts().DllExportInlines) {
     SmallVector<ConstructorUsingShadowDecl *, 4> Shadows;
     for (Decl *D : Class->decls())
       if (auto *S = dyn_cast<ConstructorUsingShadowDecl>(D))
@@ -6631,7 +6631,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
       if (MD->isDeleted())
         continue;
 
-      if (ClassExported) {
+      if (ClassExported && getLangOpts().DllExportInlines) {
         CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD);
         if (CD && CD->getInheritedConstructor()) {
           // Inherited constructors already had their base constructor's
@@ -6724,13 +6724,8 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
 
       // Do not export/import inline function when -fno-dllexport-inlines is
       // passed. But add attribute for later local static var check.
-      // Inherited constructors are marked inline but must still be exported
-      // to match MSVC behavior, so exclude them from this override.
-      bool IsInheritedCtor = false;
-      if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(MD))
-        IsInheritedCtor = (bool)CD->getInheritedConstructor();
       if (!getLangOpts().DllExportInlines && MD && MD->isInlined() &&
-          !IsInheritedCtor && TSK != TSK_ExplicitInstantiationDeclaration &&
+          TSK != TSK_ExplicitInstantiationDeclaration &&
           TSK != TSK_ExplicitInstantiationDefinition) {
         if (ClassExported) {
           NewAttr = ::new (getASTContext())
diff --git a/clang/test/CodeGenCXX/dllexport-inherited-ctor.cpp b/clang/test/CodeGenCXX/dllexport-inherited-ctor.cpp
index 03026f843eda6..9340b5db66e7d 100644
--- a/clang/test/CodeGenCXX/dllexport-inherited-ctor.cpp
+++ b/clang/test/CodeGenCXX/dllexport-inherited-ctor.cpp
@@ -225,21 +225,19 @@ struct __declspec(dllexport) CalleeCleanupChild : CalleeCleanupBase {
 // GNU-DAG: define {{.*}}dso_local dllexport {{.*}}CalleeCleanupChild{{.*}}NontrivialDtor
 
 //===----------------------------------------------------------------------===//
-// -fno-dllexport-inlines should still export inherited constructors.
-// Inherited constructors are marked inline internally but must be exported.
+// -fno-dllexport-inlines should not export inherited constructors.
+// Inherited constructors are marked inline internally.
 //===----------------------------------------------------------------------===//
 
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA at H@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA at N@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA at H@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA at M@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MLChild@@QEAA at H@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0TplChild@@QEAA at H@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0DefArgChild@@QEAA at HHH@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MixedDefChild@@QEAA at HN@Z"
-// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0AllDefChild@@QEAA at HH@Z"
-// The implicit default ctor is a regular inline method, NOT an inherited
-// constructor, so -fno-dllexport-inlines correctly suppresses it.
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA at H@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA at N@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA at H@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA at M@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0MLChild@@QEAA at H@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0TplChild@@QEAA at H@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0DefArgChild@@QEAA at HHH@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0MixedDefChild@@QEAA at HN@Z"
+// NOINLINE-NOT: define weak_odr dso_local dllexport {{.*}} @"??0AllDefChild@@QEAA at HH@Z"
 // NOINLINE-NOT: define {{.*}}dllexport{{.*}} @"??0AllDefChild@@QEAA at XZ"
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/SemaCXX/dllexport-constrained-inherited-ctor.cpp b/clang/test/SemaCXX/dllexport-constrained-inherited-ctor.cpp
index 019f0a17bdf1e..dc37948996ea7 100644
--- a/clang/test/SemaCXX/dllexport-constrained-inherited-ctor.cpp
+++ b/clang/test/SemaCXX/dllexport-constrained-inherited-ctor.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-windows-msvc -fsyntax-only -fms-extensions -verify -std=c++20 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fsyntax-only -fms-extensions -verify -std=c++20 -fno-dllexport-inlines %s
 // RUN: %clang_cc1 -triple x86_64-windows-gnu  -fsyntax-only -fms-extensions -verify -std=c++20 %s
 
 // expected-no-diagnostics



More information about the cfe-commits mailing list