r356458 - Ensure that const variables declared at namespace scope correctly have external linkage when marked as dllexport and targeting the MSVC ABI.

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 19 07:53:52 PDT 2019


Author: aaronballman
Date: Tue Mar 19 07:53:52 2019
New Revision: 356458

URL: http://llvm.org/viewvc/llvm-project?rev=356458&view=rev
Log:
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.

Added:
    cfe/trunk/test/CodeGen/dllexport-1.c
    cfe/trunk/test/Sema/dllexport-1.cpp
    cfe/trunk/test/Sema/dllexport-2.cpp
Modified:
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/SemaCXX/dllexport.cpp
    cfe/trunk/test/SemaCXX/dllimport.cpp

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=356458&r1=356457&r2=356458&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Mar 19 07:53:52 2019
@@ -5964,10 +5964,24 @@ static void checkAttributesAfterMerging(
   }
 
   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 *Re
         !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);

Added: cfe/trunk/test/CodeGen/dllexport-1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/dllexport-1.c?rev=356458&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/dllexport-1.c (added)
+++ cfe/trunk/test/CodeGen/dllexport-1.c Tue Mar 19 07:53:52 2019
@@ -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 at +1 {{'extern' variable has an initializer}}
+extern int const z = 4;
+
+int main() {
+  int a = x + y + z;
+  return a;
+}

Added: cfe/trunk/test/Sema/dllexport-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/dllexport-1.cpp?rev=356458&view=auto
==============================================================================
--- cfe/trunk/test/Sema/dllexport-1.cpp (added)
+++ cfe/trunk/test/Sema/dllexport-1.cpp Tue Mar 19 07:53:52 2019
@@ -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 at +2 {{__declspec attribute 'dllexport' is not supported}}
+#endif
+__declspec(dllexport) int const x = 3;
+
+namespace {
+namespace named {
+#ifndef MSVC
+// expected-warning at +2 {{__declspec attribute 'dllexport' is not supported}}
+#endif
+__declspec(dllexport) int const x = 3;
+}
+} // namespace
+
+namespace named1 {
+namespace {
+namespace named {
+#ifndef MSVC
+// expected-warning at +2 {{__declspec attribute 'dllexport' is not supported}}
+#endif
+__declspec(dllexport) int const x = 3;
+}
+} // namespace
+} // namespace named1

Added: cfe/trunk/test/Sema/dllexport-2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/dllexport-2.cpp?rev=356458&view=auto
==============================================================================
--- cfe/trunk/test/Sema/dllexport-2.cpp (added)
+++ cfe/trunk/test/Sema/dllexport-2.cpp Tue Mar 19 07:53:52 2019
@@ -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 at +4 {{'j' must have external linkage when declared 'dllexport'}}
+#else
+// expected-warning at +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 at +4 {{'j2' must have external linkage when declared 'dllexport'}}
+#else
+// expected-warning at +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 at +2 {{__declspec attribute 'dllexport' is not supported}}
+#endif
+__declspec(dllexport) CInt j3 = 3;

Modified: cfe/trunk/test/SemaCXX/dllexport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllexport.cpp?rev=356458&r1=356457&r2=356458&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dllexport.cpp (original)
+++ cfe/trunk/test/SemaCXX/dllexport.cpp Tue Mar 19 07:53:52 2019
@@ -69,7 +69,9 @@ __declspec(dllexport) extern int GlobalR
 // 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(dllexpor
 // 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'}}

Modified: cfe/trunk/test/SemaCXX/dllimport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllimport.cpp?rev=356458&r1=356457&r2=356458&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dllimport.cpp (original)
+++ cfe/trunk/test/SemaCXX/dllimport.cpp Tue Mar 19 07:53:52 2019
@@ -121,7 +121,9 @@ __declspec(dllimport) extern int GlobalR
 // 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(dllimpor
 // 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'}}




More information about the cfe-commits mailing list