Skip to content

Commit

Permalink
[clang] Don't inherit dllimport/dllexport to exclude_from_explicit_in…
Browse files Browse the repository at this point in the history
…stantiation members during explicit instantiation (#65961)

This is a continuation of https://reviews.llvm.org/D155713

Fixes #40363
  • Loading branch information
zmodem committed Sep 14, 2023
1 parent 602e47c commit 84216d1
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
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>;

0 comments on commit 84216d1

Please sign in to comment.