Skip to content

[clang] Don't inherit dllimport/dllexport to exclude_from_explicit_in… #65961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6602,6 +6602,13 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
if (!VD && !MD)
continue;

if ((TSK == TSK_ExplicitInstantiationDeclaration ||
TSK == TSK_ExplicitInstantiationDefinition) &&
Member->hasAttr<ExcludeFromExplicitInstantiationAttr>()) {
// Skip members excluded from instantiation.
continue;
}

if (MD) {
// Don't process deleted methods.
if (MD->isDeleted())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// RUN: %clang_cc1 -triple x86_64-unknown-windows -fms-extensions -emit-llvm -O0 -o - %s | FileCheck %s

// Test that dllimport and exclude_from_explicit_instantiation work properly
// together. Specifically, we check that when exclude_from_explicit_instantiation
// is used on a method, the compiler doesn't expect it to be provided externally
// even if it is marked with dllimport.
//
// https://github.com/llvm/llvm-project/issues/40363

#define DLLIMPORT __declspec(dllimport)
#define DLLEXPORT __declspec(dllexport)
#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))

template <class T>
struct DLLIMPORT Foo {
EXCLUDE_FROM_EXPLICIT_INSTANTIATION void x() {}
};

template <class T>
struct Bar {
EXCLUDE_FROM_EXPLICIT_INSTANTIATION void x() {}
};

extern template struct Foo<int>;
extern template struct DLLIMPORT Bar<int>;


template <class T>
struct Baz {
EXCLUDE_FROM_EXPLICIT_INSTANTIATION void f() {}
};

template struct DLLEXPORT Baz<int>;


void test(Foo<int>& foo, Bar<int>& bar, Baz<int>& baz) {
// Not imported.
// CHECK-DAG: define linkonce_odr dso_local void @"?x@?$Foo@H@@QEAAXXZ"
foo.x();

// Not imported.
// CHECK-DAG: define linkonce_odr dso_local void @"?x@?$Bar@H@@QEAAXXZ"
bar.x();

// Not exported.
// CHECK-DAG: define linkonce_odr dso_local void @"?f@?$Baz@H@@QEAAXXZ"
baz.f();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %clang_cc1 -triple x86_64-unknown-windows -fms-extensions -verify %s

// Test that an entity marked as both dllimport and exclude_from_explicit_instantiation
// isn't instantiated.

#define DLLIMPORT __declspec(dllimport)
#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))

template <class T>
struct DLLIMPORT Foo {
EXCLUDE_FROM_EXPLICIT_INSTANTIATION void x();
};

template <class T>
struct Bar {
DLLIMPORT EXCLUDE_FROM_EXPLICIT_INSTANTIATION inline void x();
};

template <class T>
void Foo<T>::x() { using Fail = typename T::fail; }

template <class T>
DLLIMPORT inline void Bar<T>::x() { using Fail = typename T::fail; }

// expected-no-diagnostics
template struct Foo<int>;
template struct Bar<int>;