https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/183515
>From 7dee8e88b0ffad0e1226fdacbfd36899dd0bda16 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Thu, 26 Feb 2026 21:49:40 +0900 Subject: [PATCH 1/4] [Clang] Drop dllexport/dllimport if conflicted with `exclude_from_explicit_instantiation` Drop `dllexport` and `dllimport` attributes from a entity that is declared with the `exclude_from_explicit_instantiation` attribute. Despite its name, the exclude attribute takes precedence over the DLL attributes, even if the entity is implicitly instantiated. This makes the semantics of the attribute simpler -- "excluded members are never DLL-exported/imported". In a non-template context, the exclude attribute is already dropped, so the DLL attributes take precedence. --- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/lib/Sema/SemaDeclCXX.cpp | 9 ++ ..._explicit_instantiation.ignore-dllattr.cpp | 98 +++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8a3b9de19ad32..3bded7c6f78e7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3784,6 +3784,9 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< def warn_redeclaration_without_import_attribute : Warning< "%q0 redeclared without 'dllimport' attribute: 'dllexport' attribute added">, InGroup<MicrosoftInconsistentDllImport>; +def warn_dllattr_ignored_exclusion_takes_precedence : Warning< + "%0 attribute ignored; %1 takes precedence">, + InGroup<IgnoredAttributes>; def warn_dllimport_dropped_from_inline_function : Warning< "%q0 redeclared inline; %1 attribute ignored">, InGroup<IgnoredAttributes>; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5837ecd6b9163..ed6da8bd317f6 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7229,6 +7229,15 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { bool HasMethodWithOverrideControl = false, HasOverridingMethodWithoutOverrideControl = false; for (auto *D : Record->decls()) { + if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) { + if (auto *DA = getDLLAttr(D)) { + Diag(DA->getRange().getBegin(), + diag::warn_dllattr_ignored_exclusion_takes_precedence) + << *DA << EA; + D->dropAttrs<DLLExportAttr, DLLImportAttr>(); + } + } + if (auto *M = dyn_cast<CXXMethodDecl>(D)) { // FIXME: We could do this check for dependent types with non-dependent // bases. diff --git a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp new file mode 100644 index 0000000000000..af15ed9f34688 --- /dev/null +++ b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp @@ -0,0 +1,98 @@ +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64-mingw -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64-cygwin -fsyntax-only -verify %s + +// Test that memberwise dllexport and dllimport are warned if the +// exclude_from_explicit_instantiation attribute is attached. + +#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation)) + +template <class T> +struct C { + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); +// expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); +// expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; +// expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; +// expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; +// expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; +// expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + + // No warnings here since nested_excluded is not instantiated. + struct EXCLUDE_ATTR nested_excluded { + __declspec(dllexport) void fn_exported(); + __declspec(dllimport) void fn_imported(); + }; + // This too. nested_exported is not instantiated. + struct __declspec(dllexport) nested_exported { + EXCLUDE_ATTR void fn_excluded(); + EXCLUDE_ATTR static int var_excluded; + }; + // The same. nested_imported is not instantiated. + struct __declspec(dllimport) nested_imported { + EXCLUDE_ATTR void fn_excluded(); + EXCLUDE_ATTR static int var_excluded; + }; + + struct nested { + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); + // expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); + // expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; + // expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; + // expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + }; +}; + +// Test that class-level dll attributes doesn't cause a warning on an excluded member. +template <class T> +struct __declspec(dllexport) DE { + EXCLUDE_ATTR void fn_excluded(); +}; +template struct DE<int>; + +template <class T> +struct __declspec(dllimport) DI { + EXCLUDE_ATTR void fn_excluded(); +}; +template struct DI<int>; + +// Test that dll attributes on explicit instantiation doesn't cause a warning on +// an excluded member. +// However, a non-template nested type may be warned on an excluded member by +// its dll attribute. +template <class T> +struct E { + EXCLUDE_ATTR void fn_excluded(); + struct EXCLUDE_ATTR nested_excluded { + __declspec(dllexport) void fn_exported(); + __declspec(dllimport) void fn_imported(); + }; + + struct __declspec(dllexport) nested_exported_1 { + // expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR void fn_excluded(); + }; + struct __declspec(dllimport) nested_imported_1 { + // expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR void fn_excluded(); + }; + + // Make sure that any warning isn't emitted if the nested type has no excluded members. + struct __declspec(dllexport) nested_exported_2 { + void fn(); + }; + struct __declspec(dllimport) nested_imported_2 { + void fn(); + }; +}; +extern template struct __declspec(dllimport) E<long>; +template struct __declspec(dllexport) E<int>; +// expected-note@-1{{in instantiation of member class 'E<int>::nested_exported_1' requested here}} +// expected-note@-2{{in instantiation of member class 'E<int>::nested_imported_1' requested here}} >From e207b7cf7bff5cbcadac9160b1b8ef630b3839b4 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Fri, 27 Feb 2026 19:19:54 +0900 Subject: [PATCH 2/4] unfold --- ..._explicit_instantiation.ignore-dllattr.cpp | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp index af15ed9f34688..1714d387d2bec 100644 --- a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp +++ b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp @@ -9,18 +9,12 @@ template <class T> struct C { - EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); -// expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); -// expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; -// expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; -// expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; -// expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; -// expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} // No warnings here since nested_excluded is not instantiated. struct EXCLUDE_ATTR nested_excluded { @@ -39,14 +33,10 @@ struct C { }; struct nested { - EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); - // expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); - // expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; - // expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; - // expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} }; }; @@ -75,12 +65,10 @@ struct E { __declspec(dllimport) void fn_imported(); }; - struct __declspec(dllexport) nested_exported_1 { - // expected-warning@-1{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct __declspec(dllexport) nested_exported_1 { // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} EXCLUDE_ATTR void fn_excluded(); }; - struct __declspec(dllimport) nested_imported_1 { - // expected-warning@-1{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct __declspec(dllimport) nested_imported_1 { // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} EXCLUDE_ATTR void fn_excluded(); }; >From e068cd10d928c8f1175f32b3c5549c7531d10779 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Fri, 27 Feb 2026 19:19:54 +0900 Subject: [PATCH 3/4] adjust the nested_exported case --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 +++ clang/lib/Sema/SemaDeclCXX.cpp | 12 +++++++++--- ...de_from_explicit_instantiation.ignore-dllattr.cpp | 8 ++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3bded7c6f78e7..072dff9b47074 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3787,6 +3787,9 @@ def warn_redeclaration_without_import_attribute : Warning< def warn_dllattr_ignored_exclusion_takes_precedence : Warning< "%0 attribute ignored; %1 takes precedence">, InGroup<IgnoredAttributes>; +def warn_exclusion_takes_precedence_over_dllattr : Warning< + "%0 attribute takes precedence over %1 attribute on the enclosing class">, + InGroup<IgnoredAttributes>; def warn_dllimport_dropped_from_inline_function : Warning< "%q0 redeclared inline; %1 attribute ignored">, InGroup<IgnoredAttributes>; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ed6da8bd317f6..ae9ab109077cb 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7231,9 +7231,15 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { for (auto *D : Record->decls()) { if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) { if (auto *DA = getDLLAttr(D)) { - Diag(DA->getRange().getBegin(), - diag::warn_dllattr_ignored_exclusion_takes_precedence) - << *DA << EA; + if (DA->isInherited()) { + Diag(EA->getLoc(), diag::warn_exclusion_takes_precedence_over_dllattr) + << EA << DA; + Diag(DA->getLoc(), diag::note_attribute); + } else { + Diag(DA->getLoc(), + diag::warn_dllattr_ignored_exclusion_takes_precedence) + << DA << EA; + } D->dropAttrs<DLLExportAttr, DLLImportAttr>(); } } diff --git a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp index 1714d387d2bec..f2a53ab9cf302 100644 --- a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp +++ b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp @@ -65,11 +65,11 @@ struct E { __declspec(dllimport) void fn_imported(); }; - struct __declspec(dllexport) nested_exported_1 { // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR void fn_excluded(); + struct __declspec(dllexport) nested_exported_1 { // expected-note{{attribute is here}} + EXCLUDE_ATTR void fn_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute takes precedence over 'dllexport' attribute on the enclosing class}} }; - struct __declspec(dllimport) nested_imported_1 { // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR void fn_excluded(); + struct __declspec(dllimport) nested_imported_1 { // expected-note{{attribute is here}} + EXCLUDE_ATTR void fn_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute takes precedence over 'dllimport' attribute on the enclosing class}} }; // Make sure that any warning isn't emitted if the nested type has no excluded members. >From 86d053cff76a3308117504df3be5b0b268b6eeb8 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Sun, 1 Mar 2026 21:04:40 +0900 Subject: [PATCH 4/4] warn only if both of an exclude attribute and a dll attribute are specified directly --- .../clang/Basic/DiagnosticSemaKinds.td | 15 +- clang/lib/Sema/SemaDeclAttr.cpp | 35 ++++ clang/lib/Sema/SemaDeclCXX.cpp | 15 -- ..._explicit_instantiation.ignore-dllattr.cpp | 156 ++++++++++++++---- 4 files changed, 165 insertions(+), 56 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 072dff9b47074..1b18c020766da 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3784,18 +3784,21 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< def warn_redeclaration_without_import_attribute : Warning< "%q0 redeclared without 'dllimport' attribute: 'dllexport' attribute added">, InGroup<MicrosoftInconsistentDllImport>; -def warn_dllattr_ignored_exclusion_takes_precedence : Warning< - "%0 attribute ignored; %1 takes precedence">, - InGroup<IgnoredAttributes>; -def warn_exclusion_takes_precedence_over_dllattr : Warning< - "%0 attribute takes precedence over %1 attribute on the enclosing class">, - InGroup<IgnoredAttributes>; def warn_dllimport_dropped_from_inline_function : Warning< "%q0 redeclared inline; %1 attribute ignored">, InGroup<IgnoredAttributes>; def warn_nothrow_attribute_ignored : Warning<"'nothrow' attribute conflicts with" " exception specification; attribute ignored">, InGroup<IgnoredAttributes>; +def warn_dllattr_ignored_exclusion_takes_precedence : Warning< + "%0 attribute ignored; %1 takes precedence">, + InGroup<IgnoredAttributes>; +def warn_attribute_ignored_on_non_member : + Warning<"%0 attribute ignored on a non-member declaration">, + InGroup<IgnoredAttributes>; +def warn_attribute_ignored_in_non_template : + Warning<"%0 attribute ignored in a non-template context">, + InGroup<IgnoredAttributes>; def warn_attribute_ignored_on_non_definition : Warning<"%0 attribute ignored on a non-definition declaration">, InGroup<IgnoredAttributes>; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3abc69d0e4b96..1b7f41061061d 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -48,6 +48,7 @@ #include "clang/Sema/SemaBPF.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaHLSL.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaM68k.h" #include "clang/Sema/SemaMIPS.h" #include "clang/Sema/SemaMSP430.h" @@ -705,6 +706,24 @@ static void handleExcludeFromExplicitInstantiationAttr(Sema &S, Decl *D, << AL << /*IsMember=*/!isa<CXXRecordDecl>(D); return; } + + if (auto *DA = getDLLAttr(D); DA && !DA->isInherited()) { + if (auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { + if (RD->isTemplated()) { + S.Diag(DA->getLoc(), + diag::warn_dllattr_ignored_exclusion_takes_precedence) + << DA << AL; + D->dropAttrs<DLLExportAttr, DLLImportAttr>(); + } else { + S.Diag(AL.getLoc(), diag::warn_attribute_ignored_in_non_template) << AL; + return; + } + } else { + S.Diag(AL.getLoc(), diag::warn_attribute_ignored_on_non_member) << AL; + return; + } + } + D->addAttr(::new (S.Context) ExcludeFromExplicitInstantiationAttr(S.Context, AL)); } @@ -6469,6 +6488,22 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { } } + if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) { + if (auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { + if (RD->isTemplated()) { + S.Diag(A.getRange().getBegin(), + diag::warn_dllattr_ignored_exclusion_takes_precedence) + << A << EA; + return; + } + S.Diag(EA->getLoc(), diag::warn_attribute_ignored_in_non_template) << EA; + D->dropAttr<ExcludeFromExplicitInstantiationAttr>(); + } else { + S.Diag(EA->getLoc(), diag::warn_attribute_ignored_on_non_member) << EA; + D->dropAttr<ExcludeFromExplicitInstantiationAttr>(); + } + } + Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport ? (Attr *)S.mergeDLLExportAttr(D, A) : (Attr *)S.mergeDLLImportAttr(D, A); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ae9ab109077cb..5837ecd6b9163 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7229,21 +7229,6 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { bool HasMethodWithOverrideControl = false, HasOverridingMethodWithoutOverrideControl = false; for (auto *D : Record->decls()) { - if (auto *EA = D->getAttr<ExcludeFromExplicitInstantiationAttr>()) { - if (auto *DA = getDLLAttr(D)) { - if (DA->isInherited()) { - Diag(EA->getLoc(), diag::warn_exclusion_takes_precedence_over_dllattr) - << EA << DA; - Diag(DA->getLoc(), diag::note_attribute); - } else { - Diag(DA->getLoc(), - diag::warn_dllattr_ignored_exclusion_takes_precedence) - << DA << EA; - } - D->dropAttrs<DLLExportAttr, DLLImportAttr>(); - } - } - if (auto *M = dyn_cast<CXXMethodDecl>(D)) { // FIXME: We could do this check for dependent types with non-dependent // bases. diff --git a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp index f2a53ab9cf302..5943f99e14cad 100644 --- a/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp +++ b/clang/test/SemaCXX/attr-exclude_from_explicit_instantiation.ignore-dllattr.cpp @@ -2,85 +2,171 @@ // RUN: %clang_cc1 -triple x86_64-mingw -fsyntax-only -verify %s // RUN: %clang_cc1 -triple x86_64-cygwin -fsyntax-only -verify %s -// Test that memberwise dllexport and dllimport are warned if the -// exclude_from_explicit_instantiation attribute is attached. +// Test that attaching the exclude_from_explicit_instantiation attribute and +// either the dllexport or dllimport attribute together causes a warning. +// One of them is ignored, depending on the context that is declared. #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation)) +// Test that exclude_from_explicit_instantiation takes precedence over +// dllexport/dllimport in a template context. template <class T> -struct C { +struct class_tmpl_no_instantiated { EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + __declspec(dllexport) EXCLUDE_ATTR void fn_exported_excluded(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + __declspec(dllimport) EXCLUDE_ATTR void fn_imported_excluded(); // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + __declspec(dllexport) EXCLUDE_ATTR static int var_exported_excluded; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + __declspec(dllimport) EXCLUDE_ATTR static int var_imported_excluded; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct __declspec(dllexport) EXCLUDE_ATTR nested_exported_excluded {}; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + struct __declspec(dllimport) EXCLUDE_ATTR nested_imported_excluded {}; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + + template <class U> + struct EXCLUDE_ATTR __declspec(dllexport) nested_tmpl_excluded_exported {}; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + template <class U> + EXCLUDE_ATTR __declspec(dllexport) static T var_template_excluded; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + template <class U> + EXCLUDE_ATTR __declspec(dllexport) void fn_template_excluded(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + + struct nested { + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + }; - // No warnings here since nested_excluded is not instantiated. struct EXCLUDE_ATTR nested_excluded { __declspec(dllexport) void fn_exported(); - __declspec(dllimport) void fn_imported(); }; - // This too. nested_exported is not instantiated. struct __declspec(dllexport) nested_exported { EXCLUDE_ATTR void fn_excluded(); - EXCLUDE_ATTR static int var_excluded; }; - // The same. nested_imported is not instantiated. struct __declspec(dllimport) nested_imported { EXCLUDE_ATTR void fn_excluded(); - EXCLUDE_ATTR static int var_excluded; }; - struct nested { + template <class U> + struct nested_tmpl { EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} - EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // expected-warning{{'dllimport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} }; }; -// Test that class-level dll attributes doesn't cause a warning on an excluded member. +// Test that a class-level dll attribute doesn't cause a warning on an excluded member. template <class T> -struct __declspec(dllexport) DE { +struct __declspec(dllexport) class_tmpl_exported { EXCLUDE_ATTR void fn_excluded(); }; -template struct DE<int>; +template struct class_tmpl_exported<int>; +void use_class_tmpl_exported() { class_tmpl_exported<long>().fn_excluded(); } template <class T> -struct __declspec(dllimport) DI { +struct __declspec(dllimport) class_tmpl_imported { EXCLUDE_ATTR void fn_excluded(); }; -template struct DI<int>; +template struct class_tmpl_imported<int>; +void use_class_tmpl_imported() { class_tmpl_imported<long>().fn_excluded(); } -// Test that dll attributes on explicit instantiation doesn't cause a warning on +// Test that a dll attribute on an explicit instantiation doesn't cause a warning on // an excluded member. -// However, a non-template nested type may be warned on an excluded member by -// its dll attribute. template <class T> -struct E { +struct class_tmpl_explicit_inst { EXCLUDE_ATTR void fn_excluded(); + EXCLUDE_ATTR static T var_excluded; struct EXCLUDE_ATTR nested_excluded { __declspec(dllexport) void fn_exported(); __declspec(dllimport) void fn_imported(); }; - struct __declspec(dllexport) nested_exported_1 { // expected-note{{attribute is here}} - EXCLUDE_ATTR void fn_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute takes precedence over 'dllexport' attribute on the enclosing class}} + struct __declspec(dllexport) nested_exported { + EXCLUDE_ATTR void fn_excluded(); }; - struct __declspec(dllimport) nested_imported_1 { // expected-note{{attribute is here}} - EXCLUDE_ATTR void fn_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute takes precedence over 'dllimport' attribute on the enclosing class}} + struct __declspec(dllimport) nested_imported { + EXCLUDE_ATTR void fn_excluded(); }; +}; +extern template struct __declspec(dllimport) class_tmpl_explicit_inst<long>; +template struct __declspec(dllexport) class_tmpl_explicit_inst<int>; + +// Test that exclude_from_explicit_instantiation is ignored in a non-template context. +struct class_nontmpl { + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + __declspec(dllexport) EXCLUDE_ATTR void fn_exported_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + __declspec(dllimport) EXCLUDE_ATTR void fn_imported_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + + EXCLUDE_ATTR __declspec(dllexport) static int var_excluded_exported; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + EXCLUDE_ATTR __declspec(dllimport) static int var_excluded_imported; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + __declspec(dllexport) EXCLUDE_ATTR static int var_exported_excluded; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + __declspec(dllimport) EXCLUDE_ATTR static int var_imported_excluded; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + + struct EXCLUDE_ATTR __declspec(dllexport) nested_excluded_exported {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + struct EXCLUDE_ATTR __declspec(dllimport) nested_excluded_imported {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + struct __declspec(dllexport) EXCLUDE_ATTR nested_exported_excluded {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + struct __declspec(dllimport) EXCLUDE_ATTR nested_imported_excluded {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + + template <class T> + struct EXCLUDE_ATTR __declspec(dllexport) class_template_excluded {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + template <class T> + EXCLUDE_ATTR __declspec(dllexport) static T var_template_excluded; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} + template <class T> + EXCLUDE_ATTR __declspec(dllexport) void fn_template_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} - // Make sure that any warning isn't emitted if the nested type has no excluded members. - struct __declspec(dllexport) nested_exported_2 { - void fn(); + struct nested { + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored in a non-template context}} }; - struct __declspec(dllimport) nested_imported_2 { - void fn(); + + struct EXCLUDE_ATTR nested_excluded { + __declspec(dllexport) void fn_excluded_exported(); }; + struct __declspec(dllexport) nested_exported { + EXCLUDE_ATTR void fn_excluded(); + }; + struct __declspec(dllimport) nested_imported { + EXCLUDE_ATTR void fn_excluded(); + }; + + template <class T> + struct nested_tmpl { + EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'dllexport' attribute ignored; 'exclude_from_explicit_instantiation' takes precedence}} + }; +}; + +// Test that exclude_from_explicit_instantiation is ignored on a non-member entity. +EXCLUDE_ATTR __declspec(dllexport) void fn_excluded_exported(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +EXCLUDE_ATTR __declspec(dllimport) void fn_excluded_imported(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +__declspec(dllexport) EXCLUDE_ATTR void fn_exported_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +__declspec(dllimport) EXCLUDE_ATTR void fn_imported_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} + +EXCLUDE_ATTR __declspec(dllexport) int var_excluded_exported; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +EXCLUDE_ATTR __declspec(dllimport) int var_excluded_imported; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +__declspec(dllexport) EXCLUDE_ATTR int var_exported_excluded; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +__declspec(dllimport) EXCLUDE_ATTR int var_imported_excluded; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} + +struct EXCLUDE_ATTR __declspec(dllexport) class_excluded_exported {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +struct EXCLUDE_ATTR __declspec(dllimport) class_excluded_imported {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +struct __declspec(dllexport) EXCLUDE_ATTR class_exported_excluded {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +struct __declspec(dllimport) EXCLUDE_ATTR class_imported_excluded {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} + +template <class T> +struct EXCLUDE_ATTR __declspec(dllexport) class_tmpl_excluded_exported {}; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +template <class T> +EXCLUDE_ATTR __declspec(dllexport) T var_template_excluded; // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} +template <class T> +EXCLUDE_ATTR __declspec(dllexport) void fn_template_excluded(); // expected-warning{{'exclude_from_explicit_instantiation' attribute ignored on a non-member declaration}} + +EXCLUDE_ATTR void fn_excluded(); + +EXCLUDE_ATTR int var_excluded; + +struct EXCLUDE_ATTR class_excluded { + __declspec(dllexport) void fn_excluded_exported(); +}; +struct __declspec(dllexport) class_exported { + EXCLUDE_ATTR void fn_excluded(); +}; +struct __declspec(dllimport) class_imported { + EXCLUDE_ATTR void fn_excluded(); }; -extern template struct __declspec(dllimport) E<long>; -template struct __declspec(dllexport) E<int>; -// expected-note@-1{{in instantiation of member class 'E<int>::nested_exported_1' requested here}} -// expected-note@-2{{in instantiation of member class 'E<int>::nested_imported_1' requested here}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
