diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 50f7e2b9221d..224c290219ef 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -282,6 +282,8 @@ def err_duplicate_mangled_name : Error< "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_non_default_visibility_dllstorage : Error< + "non-default visibility cannot be applied to '%0' 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 index f9087cdd5d4d..64a9e9d6f4c4 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1099,8 +1099,6 @@ llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) { 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,14 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, // Set visibility for definitions, and for declarations if requested globally // or set explicitly. LinkageInfo LV = D->getLinkageAndVisibility(); + if (GV->hasDLLExportStorageClass() || GV->hasDLLImportStorageClass()) { + // Reject explicit non-default visibility on dllexport/dllimport. + if (LV.isVisibilityExplicit() && LV.getVisibility() != DefaultVisibility) + getDiags().Report(D->getLocation(), + diag::err_non_default_visibility_dllstorage) + << (GV->hasDLLExportStorageClass() ? "dllexport" : "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 index 8f34afbb801f..0e3c32ec9aec 100644 --- a/clang/test/CodeGenCXX/dllstorage-visibility.cpp +++ b/clang/test/CodeGenCXX/dllstorage-visibility.cpp @@ -4,10 +4,18 @@ // 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 + #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 +32,17 @@ __attribute__((dllexport)) void exported() {} // GNU-DAG: define weak_odr dso_local dllexport void @_Z15exported_inlinev( __declspec(dllexport) inline void exported_inline() {} USE(exported_inline) + +#if defined(ERR1) +// expected-error@+1 {{non-default visibility cannot be applied to 'dllimport' declaration}} +__attribute__((dllimport)) HIDDEN void imported_hidden(); + +__attribute__((dllexport)) DEFAULT void exported_default() {} +// expected-error@+1 {{non-default visibility cannot be applied to 'dllexport' declaration}} +__attribute__((dllexport)) HIDDEN void exported_hidden() { imported_hidden(); } +#elif defined(ERR2) +struct PROTECTED C { + // expected-error@+1 {{non-default visibility cannot be applied to 'dllexport' declaration}} + __attribute__((dllexport)) void exported_protected() {} +}; +#endif