[Clang] Ensure child classes export inherited constructors from base classes (#182706)
Inherited constructors in `dllexport` classes are now exported for ABI-compatible cases, matching MSVC behavior. Constructors with variadic arguments or callee-cleanup parameters are not yet supported and produce a warning. This aims to partially resolve https://github.com/llvm/llvm-project/issues/162640. Assisted by : Cursor // Claude Opus 4.6
This commit is contained in:
parent
b989713cd2
commit
6811a83c81
@ -335,6 +335,9 @@ Bug Fixes to C++ Support
|
||||
when used inside decltype in the return type. (#GH180460)
|
||||
- Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type vectors in ``constexpr``. (#GH180044)
|
||||
- Fixed a crash on ``typeid`` of incomplete local types during template instantiation. (#GH63242), (#GH176397)
|
||||
- Inherited constructors in ``dllexport`` classes are now exported for ABI-compatible cases, matching
|
||||
MSVC behavior. Constructors with variadic arguments or callee-cleanup parameters are not yet supported
|
||||
and produce a warning. (#GH162640)
|
||||
|
||||
- Fix initialization of GRO when GRO-return type mismatches, as part of CWG2563. (#GH98744)
|
||||
|
||||
|
||||
@ -3935,6 +3935,11 @@ def warn_dllexport_on_decl_ignored : Warning<
|
||||
InGroup<IgnoredAttributes>;
|
||||
def note_dllexport_on_decl : Note<
|
||||
"'dllexport' attribute on the declaration is ignored">;
|
||||
def warn_dllexport_inherited_ctor_unsupported : Warning<
|
||||
"exporting inherited constructor is not yet supported; "
|
||||
"'dllexport' ignored on inherited constructor with "
|
||||
"%select{variadic arguments|callee-cleanup parameters}0">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_attribute_exclude_from_explicit_instantiation_local_class : Warning<
|
||||
"%0 attribute ignored on local class%select{| member}1">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
|
||||
@ -13013,11 +13013,20 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
|
||||
|
||||
if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
|
||||
isa<CXXConstructorDecl>(FD) &&
|
||||
cast<CXXConstructorDecl>(FD)->isInheritingConstructor())
|
||||
// Our approach to inheriting constructors is fundamentally different from
|
||||
// that used by the MS ABI, so keep our inheriting constructor thunks
|
||||
// internal rather than trying to pick an unambiguous mangling for them.
|
||||
cast<CXXConstructorDecl>(FD)->isInheritingConstructor() &&
|
||||
!FD->hasAttr<DLLExportAttr>()) {
|
||||
// Both Clang and MSVC implement inherited constructors as forwarding
|
||||
// thunks that delegate to the base constructor. Keep non-dllexport
|
||||
// inheriting constructor thunks internal since they are not needed
|
||||
// outside the translation unit.
|
||||
//
|
||||
// dllexport inherited constructors are exempted so they are externally
|
||||
// visible, matching MSVC's export behavior. Inherited constructors
|
||||
// whose parameters prevent ABI-compatible forwarding (e.g. callee-
|
||||
// cleanup types) are excluded from export in Sema to avoid silent
|
||||
// runtime mismatches.
|
||||
return GVA_Internal;
|
||||
}
|
||||
|
||||
return GVA_DiscardableODR;
|
||||
}
|
||||
|
||||
@ -260,6 +260,21 @@ namespace {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit dllexport inherited constructors. These are synthesized during
|
||||
// Sema (in checkClassLevelDLLAttribute) but have no written definition,
|
||||
// so they must be emitted now while visiting the class definition.
|
||||
if (auto *RD = dyn_cast<CXXRecordDecl>(D);
|
||||
RD && RD->hasAttr<DLLExportAttr>()) {
|
||||
for (Decl *Member : RD->decls()) {
|
||||
if (auto *CD = dyn_cast<CXXConstructorDecl>(Member)) {
|
||||
if (CD->getInheritedConstructor() && CD->hasAttr<DLLExportAttr>() &&
|
||||
!CD->isDeleted())
|
||||
Builder->EmitTopLevelDecl(CD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For OpenMP emit declare reduction functions, if required.
|
||||
if (Ctx->getLangOpts().OpenMP) {
|
||||
for (Decl *Member : D->decls()) {
|
||||
|
||||
@ -6588,6 +6588,19 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
|
||||
// Force declaration of implicit members so they can inherit the attribute.
|
||||
ForceDeclarationOfImplicitMembers(Class);
|
||||
|
||||
// Inherited constructors are created lazily; force their creation now so the
|
||||
// loop below can propagate the DLL attribute to them.
|
||||
if (ClassExported) {
|
||||
SmallVector<ConstructorUsingShadowDecl *, 4> Shadows;
|
||||
for (Decl *D : Class->decls())
|
||||
if (auto *S = dyn_cast<ConstructorUsingShadowDecl>(D))
|
||||
Shadows.push_back(S);
|
||||
for (ConstructorUsingShadowDecl *S : Shadows)
|
||||
if (auto *BC = dyn_cast<CXXConstructorDecl>(S->getTargetDecl());
|
||||
BC && !BC->isDeleted())
|
||||
findInheritingConstructor(Class->getLocation(), BC, S);
|
||||
}
|
||||
|
||||
// FIXME: MSVC's docs say all bases must be exportable, but this doesn't
|
||||
// seem to be true in practice?
|
||||
|
||||
@ -6604,13 +6617,52 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
|
||||
if (MD->isDeleted())
|
||||
continue;
|
||||
|
||||
// Don't export inherited constructors whose parameters prevent ABI-
|
||||
// compatible forwarding. When canEmitDelegateCallArgs (in CodeGen)
|
||||
// returns false, Clang inlines the constructor body instead of
|
||||
// emitting a forwarding thunk, producing code that is not ABI-
|
||||
// compatible with MSVC. Suppress the export and warn so the user
|
||||
// gets a linker error rather than a silent runtime mismatch.
|
||||
if (ClassExported) {
|
||||
if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
|
||||
if (CD->getInheritedConstructor()) {
|
||||
if (CD->isVariadic()) {
|
||||
Diag(CD->getLocation(),
|
||||
diag::warn_dllexport_inherited_ctor_unsupported)
|
||||
<< /*variadic=*/0;
|
||||
continue;
|
||||
}
|
||||
if (Context.getTargetInfo()
|
||||
.getCXXABI()
|
||||
.areArgsDestroyedLeftToRightInCallee()) {
|
||||
bool HasCalleeCleanupParam = false;
|
||||
for (const auto *P : CD->parameters())
|
||||
if (P->needsDestruction(Context)) {
|
||||
HasCalleeCleanupParam = true;
|
||||
break;
|
||||
}
|
||||
if (HasCalleeCleanupParam) {
|
||||
Diag(CD->getLocation(),
|
||||
diag::warn_dllexport_inherited_ctor_unsupported)
|
||||
<< /*callee-cleanup=*/1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MD->isInlined()) {
|
||||
// MinGW does not import or export inline methods. But do it for
|
||||
// template instantiations.
|
||||
// template instantiations and inherited constructors (which are
|
||||
// marked inline but must be exported to match MSVC behavior).
|
||||
if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
|
||||
TSK != TSK_ExplicitInstantiationDeclaration &&
|
||||
TSK != TSK_ExplicitInstantiationDefinition)
|
||||
continue;
|
||||
TSK != TSK_ExplicitInstantiationDefinition) {
|
||||
if (auto *CD = dyn_cast<CXXConstructorDecl>(MD);
|
||||
!CD || !CD->getInheritedConstructor())
|
||||
continue;
|
||||
}
|
||||
|
||||
// MSVC versions before 2015 don't export the move assignment operators
|
||||
// and move constructor, so don't attempt to import/export them if
|
||||
@ -6643,8 +6695,13 @@ 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() &&
|
||||
TSK != TSK_ExplicitInstantiationDeclaration &&
|
||||
!IsInheritedCtor && TSK != TSK_ExplicitInstantiationDeclaration &&
|
||||
TSK != TSK_ExplicitInstantiationDefinition) {
|
||||
if (ClassExported) {
|
||||
NewAttr = ::new (getASTContext())
|
||||
|
||||
243
clang/test/CodeGenCXX/dllexport-inherited-ctor.cpp
Normal file
243
clang/test/CodeGenCXX/dllexport-inherited-ctor.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-windows-msvc -emit-llvm -std=c++17 -fms-extensions -O0 -o - %s | FileCheck --check-prefix=MSVC %s
|
||||
// RUN: %clang_cc1 -no-enable-noundef-analysis -triple i686-windows-msvc -emit-llvm -std=c++17 -fms-extensions -O0 -o - %s | FileCheck --check-prefix=M32 %s
|
||||
// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-windows-gnu -emit-llvm -std=c++17 -fms-extensions -O0 -o - %s | FileCheck --check-prefix=GNU %s
|
||||
// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-windows-msvc -emit-llvm -std=c++17 -fms-extensions -fno-dllexport-inlines -O0 -o - %s | FileCheck --check-prefix=NOINLINE %s
|
||||
|
||||
// Test that inherited constructors via 'using Base::Base' in a dllexport
|
||||
// class are properly exported (https://github.com/llvm/llvm-project/issues/162640).
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic: both base and child exported, simple parameter types.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct __declspec(dllexport) Base {
|
||||
Base(int);
|
||||
Base(double);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) Child : public Base {
|
||||
using Base::Base;
|
||||
};
|
||||
|
||||
// The inherited constructors Child(int) and Child(double) should be exported.
|
||||
// Verify the thunk bodies delegate to the base constructor with the correct
|
||||
// arguments, ensuring ABI compatibility with MSVC-compiled callers.
|
||||
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA@H@Z"(ptr {{.*}} %this, i32 %0)
|
||||
// MSVC-DAG: call {{.*}} @"??0Base@@QEAA@H@Z"(ptr {{.*}} %this{{.*}}, i32
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA@N@Z"(ptr {{.*}} %this, double %0)
|
||||
// MSVC-DAG: call {{.*}} @"??0Base@@QEAA@N@Z"(ptr {{.*}} %this{{.*}}, double
|
||||
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QAE@H@Z"
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QAE@N@Z"
|
||||
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN5ChildCI14BaseEi(
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN5ChildCI14BaseEd(
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Non-exported class should not export inherited ctors.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct NonExportedBase {
|
||||
NonExportedBase(int);
|
||||
};
|
||||
|
||||
struct NonExportedChild : public NonExportedBase {
|
||||
using NonExportedBase::NonExportedBase;
|
||||
};
|
||||
|
||||
// MSVC-NOT: dllexport{{.*}}NonExportedChild
|
||||
// M32-NOT: dllexport{{.*}}NonExportedChild
|
||||
// GNU-NOT: dllexport{{.*}}NonExportedChild
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Only the derived class is dllexport, base is not.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct PlainBase {
|
||||
PlainBase(int);
|
||||
PlainBase(float);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) ExportedChild : public PlainBase {
|
||||
using PlainBase::PlainBase;
|
||||
};
|
||||
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA@H@Z"
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA@M@Z"
|
||||
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QAE@H@Z"
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QAE@M@Z"
|
||||
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN13ExportedChildCI19PlainBaseEi(
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN13ExportedChildCI19PlainBaseEf(
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Multi-level inheritance: A -> B -> C with using at each level.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct MLBase {
|
||||
MLBase(int);
|
||||
};
|
||||
|
||||
struct MLMiddle : MLBase {
|
||||
using MLBase::MLBase;
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) MLChild : MLMiddle {
|
||||
using MLMiddle::MLMiddle;
|
||||
};
|
||||
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MLChild@@QEAA@H@Z"
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MLChild@@QAE@H@Z"
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN7MLChildCI16MLBaseEi(
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Class template specialization with inherited constructors.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T>
|
||||
struct TplBase {
|
||||
TplBase(T);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) TplChild : TplBase<int> {
|
||||
using TplBase<int>::TplBase;
|
||||
};
|
||||
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0TplChild@@QEAA@H@Z"
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0TplChild@@QAE@H@Z"
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN8TplChildCI17TplBaseIiEEi(
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Default arguments: thunk takes the full parameter list.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct DefArgBase {
|
||||
DefArgBase(int a, int b = 10, int c = 20);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) DefArgChild : DefArgBase {
|
||||
using DefArgBase::DefArgBase;
|
||||
};
|
||||
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0DefArgChild@@QEAA@HHH@Z"(ptr {{.*}} %this, i32 %0, i32 %1, i32 %2)
|
||||
// MSVC-DAG: call {{.*}} @"??0DefArgBase@@QEAA@HHH@Z"(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32
|
||||
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0DefArgChild@@QAE@HHH@Z"
|
||||
// M32-DAG: call {{.*}} @"??0DefArgBase@@QAE@HHH@Z"(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32
|
||||
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN11DefArgChildCI110DefArgBaseEiii(
|
||||
// GNU-DAG: call {{.*}} @_ZN10DefArgBaseC2Eiii(ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Default arguments with mixed types.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct MixedDefBase {
|
||||
MixedDefBase(int a, double b = 3.14);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) MixedDefChild : MixedDefBase {
|
||||
using MixedDefBase::MixedDefBase;
|
||||
};
|
||||
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MixedDefChild@@QEAA@HN@Z"(ptr {{.*}} %this, i32 %0, double %1)
|
||||
// MSVC-DAG: call {{.*}} @"??0MixedDefBase@@QEAA@HN@Z"(ptr {{.*}}, i32 {{.*}}, double
|
||||
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MixedDefChild@@QAE@HN@Z"
|
||||
// M32-DAG: call {{.*}} @"??0MixedDefBase@@QAE@HN@Z"(ptr {{.*}}, i32 {{.*}}, double
|
||||
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN13MixedDefChildCI112MixedDefBaseEid(
|
||||
// GNU-DAG: call {{.*}} @_ZN12MixedDefBaseC2Eid(ptr {{.*}}, i32 {{.*}}, double
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// All parameters have defaults. The inherited constructor takes the full
|
||||
// parameter list. The implicit default constructor also gets exported, with
|
||||
// default argument values baked in.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct AllDefBase {
|
||||
AllDefBase(int a = 1, int b = 2);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) AllDefChild : AllDefBase {
|
||||
using AllDefBase::AllDefBase;
|
||||
};
|
||||
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0AllDefChild@@QEAA@HH@Z"(ptr {{.*}} %this, i32 %0, i32 %1)
|
||||
// MSVC-DAG: define weak_odr dso_local dllexport {{.*}} @"??0AllDefChild@@QEAA@XZ"(ptr {{.*}} %this)
|
||||
// MSVC-DAG: call {{.*}} @"??0AllDefBase@@QEAA@HH@Z"(ptr {{.*}}, i32 1, i32 2)
|
||||
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0AllDefChild@@QAE@HH@Z"
|
||||
// M32-DAG: call {{.*}} @"??0AllDefBase@@QAE@HH@Z"(ptr {{.*}}, i32 %
|
||||
// M32-DAG: define weak_odr dso_local dllexport {{.*}} @"??0AllDefChild@@QAE@XZ"
|
||||
// M32-DAG: call {{.*}} @"??0AllDefBase@@QAE@HH@Z"(ptr {{.*}}, i32 1, i32 2)
|
||||
|
||||
// GNU does not emit an implicit default constructor unless it is used.
|
||||
// Only the inherited constructor with the full parameter list is exported.
|
||||
// GNU-DAG: define {{.*}}dso_local dllexport {{.*}} @_ZN11AllDefChildCI110AllDefBaseEii(
|
||||
// GNU-DAG: call {{.*}} @_ZN10AllDefBaseC2Eii(ptr {{.*}}, i32 %{{.*}}, i32 %
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Variadic constructor: inherited variadic constructors cannot be exported
|
||||
// because delegate forwarding is not supported for variadic arguments.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct VariadicBase {
|
||||
VariadicBase(int, ...);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) VariadicChild : VariadicBase {
|
||||
using VariadicBase::VariadicBase;
|
||||
};
|
||||
|
||||
// The variadic inherited constructor (int, ...) should NOT be exported.
|
||||
// Match specifically to avoid matching implicitly exported copy/move ctors.
|
||||
// MSVC-NOT: dllexport{{.*}}??0VariadicChild@@QEAA@H
|
||||
// M32-NOT: dllexport{{.*}}??0VariadicChild@@QAE@H
|
||||
// GNU-NOT: dllexport{{.*}}VariadicChildCI1{{.*}}Eiz
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Callee-cleanup parameter: struct with non-trivial destructor passed by value.
|
||||
// canEmitDelegateCallArgs returns false for this case, so the inherited
|
||||
// constructor must NOT be exported to avoid ABI incompatibility with MSVC.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct NontrivialDtor {
|
||||
int x;
|
||||
~NontrivialDtor();
|
||||
};
|
||||
|
||||
struct CalleeCleanupBase {
|
||||
CalleeCleanupBase(NontrivialDtor);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) CalleeCleanupChild : CalleeCleanupBase {
|
||||
using CalleeCleanupBase::CalleeCleanupBase;
|
||||
};
|
||||
|
||||
// The inherited constructor should NOT be exported on MSVC targets because the
|
||||
// parameter requires callee-cleanup, making the thunk ABI-incompatible.
|
||||
// On GNU targets the callee-cleanup issue does not apply, so export is fine.
|
||||
// MSVC-NOT: dllexport{{.*}}CalleeCleanupChild{{.*}}NontrivialDtor
|
||||
// M32-NOT: dllexport{{.*}}CalleeCleanupChild{{.*}}NontrivialDtor
|
||||
// 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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA@H@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0Child@@QEAA@N@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA@H@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0ExportedChild@@QEAA@M@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MLChild@@QEAA@H@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0TplChild@@QEAA@H@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0DefArgChild@@QEAA@HHH@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0MixedDefChild@@QEAA@HN@Z"
|
||||
// NOINLINE-DAG: define weak_odr dso_local dllexport {{.*}} @"??0AllDefChild@@QEAA@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 {{.*}}dllexport{{.*}} @"??0AllDefChild@@QEAA@XZ"
|
||||
@ -1131,3 +1131,28 @@ template<typename T> template<typename U> __declspec(dllexport) constexpr int CT
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The MS ABI doesn't provide a stable mangling for lambdas, so they can't be imported or exported.
|
||||
auto Lambda = []() __declspec(dllexport) -> bool { return true; }; // non-gnu-error {{lambda cannot be declared 'dllexport'}}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Inherited constructors: unsupported export warnings
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct VariadicBase {
|
||||
VariadicBase(int, ...);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) VariadicChild : VariadicBase {
|
||||
using VariadicBase::VariadicBase; // expected-warning{{exporting inherited constructor is not yet supported; 'dllexport' ignored on inherited constructor with variadic arguments}}
|
||||
};
|
||||
|
||||
struct NontrivialDtorParam {
|
||||
int x;
|
||||
~NontrivialDtorParam();
|
||||
};
|
||||
|
||||
struct CalleeCleanupBase {
|
||||
CalleeCleanupBase(NontrivialDtorParam);
|
||||
};
|
||||
|
||||
struct __declspec(dllexport) CalleeCleanupChild : CalleeCleanupBase {
|
||||
using CalleeCleanupBase::CalleeCleanupBase; // ms-warning{{exporting inherited constructor is not yet supported; 'dllexport' ignored on inherited constructor with callee-cleanup parameters}}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user