forked from OSchip/llvm-project
Ensure that const variables declared at namespace scope correctly have external linkage when marked as dllexport and targeting the MSVC ABI.
Patch thanks to Zahira Ammarguellat. llvm-svn: 356458
This commit is contained in:
parent
7045c6f0b5
commit
165435ffa0
|
@ -5964,10 +5964,24 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
|
|||
}
|
||||
|
||||
if (const InheritableAttr *Attr = getDLLAttr(&ND)) {
|
||||
auto *VD = dyn_cast<VarDecl>(&ND);
|
||||
bool IsAnonymousNS = false;
|
||||
bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft();
|
||||
if (VD) {
|
||||
const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(VD->getDeclContext());
|
||||
while (NS && !IsAnonymousNS) {
|
||||
IsAnonymousNS = NS->isAnonymousNamespace();
|
||||
NS = dyn_cast<NamespaceDecl>(NS->getParent());
|
||||
}
|
||||
}
|
||||
// dll attributes require external linkage. Static locals may have external
|
||||
// linkage but still cannot be explicitly imported or exported.
|
||||
auto *VD = dyn_cast<VarDecl>(&ND);
|
||||
if (!ND.isExternallyVisible() || (VD && VD->isStaticLocal())) {
|
||||
// In Microsoft mode, a variable defined in anonymous namespace must have
|
||||
// external linkage in order to be exported.
|
||||
bool AnonNSInMicrosoftMode = IsAnonymousNS && IsMicrosoft;
|
||||
if ((ND.isExternallyVisible() && AnonNSInMicrosoftMode) ||
|
||||
(!AnonNSInMicrosoftMode &&
|
||||
(!ND.isExternallyVisible() || (VD && VD->isStaticLocal())))) {
|
||||
S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern)
|
||||
<< &ND << Attr;
|
||||
ND.setInvalidDecl();
|
||||
|
@ -11376,6 +11390,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
|||
!isTemplateInstantiation(VDecl->getTemplateSpecializationKind()))
|
||||
Diag(VDecl->getLocation(), diag::warn_extern_init);
|
||||
|
||||
// In Microsoft C++ mode, a const variable defined in namespace scope has
|
||||
// external linkage by default if the variable is declared with
|
||||
// __declspec(dllexport).
|
||||
if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
|
||||
getLangOpts().CPlusPlus && VDecl->getType().isConstQualified() &&
|
||||
VDecl->hasAttr<DLLExportAttr>() && VDecl->getDefinition())
|
||||
VDecl->setStorageClass(SC_Extern);
|
||||
|
||||
// C99 6.7.8p4. All file scoped initializers need to be constant.
|
||||
if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl())
|
||||
CheckForConstantInitializer(Init, DclT);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -fms-extensions -Wno-ignored-attributes -Wno-extern-initializer -o - %s | FileCheck %s -check-prefix CHECK-LNX
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -fms-extensions -o - -DMSVC %s | FileCheck %s -check-prefix CHECK-MSVC
|
||||
|
||||
// Export const variable.
|
||||
|
||||
// CHECK-MSVC: @x = dso_local dllexport constant i32 3, align 4
|
||||
// CHECK-LNX: @x = constant i32 3, align 4
|
||||
|
||||
// CHECK-MSVC: @z = dso_local constant i32 4, align 4
|
||||
// CHECK-LNX: @z = constant i32 4, align 4
|
||||
|
||||
// CHECK-MSVC: @y = common dso_local dllexport global i32 0, align 4
|
||||
// CHECK-LNX: @y = common global i32 0, align 4
|
||||
|
||||
__declspec(dllexport) int const x = 3;
|
||||
__declspec(dllexport) const int y;
|
||||
|
||||
// expected-warning@+1 {{'extern' variable has an initializer}}
|
||||
extern int const z = 4;
|
||||
|
||||
int main() {
|
||||
int a = x + y + z;
|
||||
return a;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -fms-extensions -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsyntax-only -fms-extensions -verify %s -DMSVC
|
||||
|
||||
// Export const variable initialization.
|
||||
|
||||
#ifdef MSVC
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
#ifndef MSVC
|
||||
// expected-warning@+2 {{__declspec attribute 'dllexport' is not supported}}
|
||||
#endif
|
||||
__declspec(dllexport) int const x = 3;
|
||||
|
||||
namespace {
|
||||
namespace named {
|
||||
#ifndef MSVC
|
||||
// expected-warning@+2 {{__declspec attribute 'dllexport' is not supported}}
|
||||
#endif
|
||||
__declspec(dllexport) int const x = 3;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace named1 {
|
||||
namespace {
|
||||
namespace named {
|
||||
#ifndef MSVC
|
||||
// expected-warning@+2 {{__declspec attribute 'dllexport' is not supported}}
|
||||
#endif
|
||||
__declspec(dllexport) int const x = 3;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace named1
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -fms-extensions -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsyntax-only -fms-extensions -verify %s -DMSVC
|
||||
|
||||
// Export const variable.
|
||||
|
||||
#ifdef MSVC
|
||||
// expected-error@+4 {{'j' must have external linkage when declared 'dllexport'}}
|
||||
#else
|
||||
// expected-warning@+2 {{__declspec attribute 'dllexport' is not supported}}
|
||||
#endif
|
||||
__declspec(dllexport) int const j; // expected-error {{default initialization of an object of const type 'const int'}}
|
||||
|
||||
// With typedef
|
||||
typedef const int CInt;
|
||||
|
||||
#ifdef MSVC
|
||||
// expected-error@+4 {{'j2' must have external linkage when declared 'dllexport'}}
|
||||
#else
|
||||
// expected-warning@+2 {{__declspec attribute 'dllexport' is not supported}}
|
||||
#endif
|
||||
__declspec(dllexport) CInt j2; //expected-error {{default initialization of an object of const type 'CInt'}}
|
||||
|
||||
#ifndef MSVC
|
||||
// expected-warning@+2 {{__declspec attribute 'dllexport' is not supported}}
|
||||
#endif
|
||||
__declspec(dllexport) CInt j3 = 3;
|
|
@ -69,7 +69,9 @@ __declspec(dllexport) extern int GlobalRedecl4; // expected-warning{{redeclarati
|
|||
// External linkage is required.
|
||||
__declspec(dllexport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllexport'}}
|
||||
__declspec(dllexport) Internal InternalTypeGlobal; // expected-error{{'InternalTypeGlobal' must have external linkage when declared 'dllexport'}}
|
||||
#ifndef MS
|
||||
namespace { __declspec(dllexport) int InternalGlobal; } // expected-error{{'(anonymous namespace)::InternalGlobal' must have external linkage when declared 'dllexport'}}
|
||||
#endif
|
||||
namespace ns { __declspec(dllexport) int ExternalGlobal; }
|
||||
|
||||
__declspec(dllexport) auto InternalAutoTypeGlobal = Internal(); // expected-error{{'InternalAutoTypeGlobal' must have external linkage when declared 'dllexport'}}
|
||||
|
@ -124,7 +126,9 @@ template<typename T> __declspec(dllexport) extern int VarTmplRedecl3; // expecte
|
|||
// External linkage is required.
|
||||
template<typename T> __declspec(dllexport) static int StaticVarTmpl; // expected-error{{'StaticVarTmpl' must have external linkage when declared 'dllexport'}}
|
||||
template<typename T> __declspec(dllexport) Internal InternalTypeVarTmpl; // expected-error{{'InternalTypeVarTmpl' must have external linkage when declared 'dllexport'}}
|
||||
#ifndef MS
|
||||
namespace { template<typename T> __declspec(dllexport) int InternalVarTmpl; } // expected-error{{'(anonymous namespace)::InternalVarTmpl' must have external linkage when declared 'dllexport'}}
|
||||
#endif
|
||||
namespace ns { template<typename T> __declspec(dllexport) int ExternalVarTmpl = 1; }
|
||||
|
||||
template<typename T> __declspec(dllexport) auto InternalAutoTypeVarTmpl = Internal(); // expected-error{{'InternalAutoTypeVarTmpl' must have external linkage when declared 'dllexport'}}
|
||||
|
|
|
@ -121,7 +121,9 @@ __declspec(dllimport) extern int GlobalRedecl5; // expected-warning{{redeclarati
|
|||
// External linkage is required.
|
||||
__declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllimport'}}
|
||||
__declspec(dllimport) Internal InternalTypeGlobal; // expected-error{{'InternalTypeGlobal' must have external linkage when declared 'dllimport'}}
|
||||
#ifndef MS
|
||||
namespace { __declspec(dllimport) int InternalGlobal; } // expected-error{{'(anonymous namespace)::InternalGlobal' must have external linkage when declared 'dllimport'}}
|
||||
#endif
|
||||
namespace ns { __declspec(dllimport) int ExternalGlobal; }
|
||||
|
||||
__declspec(dllimport) auto InternalAutoTypeGlobal = Internal(); // expected-error{{'InternalAutoTypeGlobal' must have external linkage when declared 'dllimport'}}
|
||||
|
@ -213,7 +215,9 @@ template<typename T> __declspec(dllimport) extern int VarTmplRedecl4; // expecte
|
|||
// External linkage is required.
|
||||
template<typename T> __declspec(dllimport) static int StaticVarTmpl; // expected-error{{'StaticVarTmpl' must have external linkage when declared 'dllimport'}}
|
||||
template<typename T> __declspec(dllimport) Internal InternalTypeVarTmpl; // expected-error{{'InternalTypeVarTmpl' must have external linkage when declared 'dllimport'}}
|
||||
#ifndef MS
|
||||
namespace { template<typename T> __declspec(dllimport) int InternalVarTmpl; } // expected-error{{'(anonymous namespace)::InternalVarTmpl' must have external linkage when declared 'dllimport'}}
|
||||
#endif
|
||||
namespace ns { template<typename T> __declspec(dllimport) int ExternalVarTmpl; }
|
||||
|
||||
template<typename T> __declspec(dllimport) auto InternalAutoTypeVarTmpl = Internal(); // expected-error{{definition of dllimport data}} // expected-error{{'InternalAutoTypeVarTmpl' must have external linkage when declared 'dllimport'}}
|
||||
|
|
Loading…
Reference in New Issue