diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -282,6 +282,10 @@ "definition with same mangled name '%0' as another definition">; def err_cyclic_alias : Error< "%select{alias|ifunc}0 definition is part of a cycle">; +def err_hidden_visibility_dllexport : Error< + "hidden visibility cannot be applied to 'dllexport' declaration">; +def err_non_default_visibility_dllimport : Error< + "non-default visibility cannot be applied to 'dllimport' declaration">; def err_ifunc_resolver_return : Error< "ifunc resolver function must return a pointer">; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1099,8 +1099,6 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const { - if (GV->hasDLLExportStorageClass() || GV->hasDLLImportStorageClass()) - return; // Internal definitions always have default visibility. if (GV->hasLocalLinkage()) { GV->setVisibility(llvm::GlobalValue::DefaultVisibility); @@ -1111,6 +1109,21 @@ // Set visibility for definitions, and for declarations if requested globally // or set explicitly. LinkageInfo LV = D->getLinkageAndVisibility(); + if (GV->hasDLLExportStorageClass() || GV->hasDLLImportStorageClass()) { + // Reject incompatible dlllstorage and visibility annotations. + if (!LV.isVisibilityExplicit()) + return; + if (GV->hasDLLExportStorageClass()) { + if (LV.getVisibility() == HiddenVisibility) + getDiags().Report(D->getLocation(), + diag::err_hidden_visibility_dllexport); + } else if (LV.getVisibility() != DefaultVisibility) { + getDiags().Report(D->getLocation(), + diag::err_non_default_visibility_dllimport); + } + return; + } + if (LV.isVisibilityExplicit() || getLangOpts().SetVisibilityForExternDecls || !GV->isDeclarationForLinker()) GV->setVisibility(GetLLVMVisibility(LV.getVisibility())); diff --git a/clang/test/CodeGenCXX/dllstorage-visibility.cpp b/clang/test/CodeGenCXX/dllstorage-visibility.cpp --- a/clang/test/CodeGenCXX/dllstorage-visibility.cpp +++ b/clang/test/CodeGenCXX/dllstorage-visibility.cpp @@ -4,10 +4,19 @@ // RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-gnu -fdeclspec -fvisibility-inlines-hidden -o - %s | FileCheck %s --check-prefix=GNU // RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-gnu -fdeclspec -fvisibility=hidden -o - %s | FileCheck %s --check-prefix=GNU +// RUN: %clang_cc1 -emit-llvm-only -verify -triple x86_64-windows-gnu -fdeclspec -DERR1 -o - %s +// RUN: %clang_cc1 -emit-llvm-only -verify -triple x86_64-windows-gnu -fdeclspec -fvisibility=hidden -DERR1 -o - %s +// RUN: %clang_cc1 -emit-llvm-only -verify -triple x86_64-windows-gnu -fdeclspec -DERR2 -o - %s +// RUN: %clang_cc1 -emit-llvm-only -verify -triple x86_64-windows-gnu -fdeclspec -DERR3 -o - %s + #define CONCAT2(x, y) x##y #define CONCAT(x, y) CONCAT2(x, y) #define USE(func) void CONCAT(use, __LINE__)() { func(); } +#define HIDDEN __attribute__((visibility("hidden"))) +#define PROTECTED __attribute__((visibility("protected"))) +#define DEFAULT __attribute__((visibility("default"))) + // MSVC-DAG: declare dllimport void @"?bar@foo@@QEAAXXZ"( // GNU-DAG: define linkonce_odr hidden void @_ZN3foo3barEv( @@ -24,3 +33,31 @@ // GNU-DAG: define weak_odr dso_local dllexport void @_Z15exported_inlinev( __declspec(dllexport) inline void exported_inline() {} USE(exported_inline) + +__attribute__((dllexport)) DEFAULT void exported_default() {} + +// MSVC-DAG: define protected dllexport void @"?exported_protected@@YAXXZ"( +// GNU-DAG: define protected dllexport void @_Z18exported_protectedv( +#pragma GCC visibility push(protected) +__attribute__((dllexport)) void exported_protected() {} +#pragma GCC visibility pop + +#if defined(ERR1) +// expected-error@+1 {{non-default visibility cannot be applied to 'dllimport' declaration}} +__attribute__((dllimport)) HIDDEN void imported_hidden(); + +// expected-error@+1 {{hidden visibility cannot be applied to 'dllexport' declaration}} +__attribute__((dllexport)) HIDDEN void exported_hidden() { imported_hidden(); } + +#elif defined(ERR2) +// expected-error@+1 {{non-default visibility cannot be applied to 'dllimport' declaration}} +__attribute__((dllimport)) PROTECTED void imported_protected(); + +void foo() { imported_protected(); } + +#elif defined(ERR3) +struct HIDDEN C2 { + // expected-error@+1 {{hidden visibility cannot be applied to 'dllexport' declaration}} + __attribute__((dllexport)) void exported_hidden() {} +}; +#endif