From 15413ea02ba202f2de500059930cc60cf1af9ae4 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 20 May 2015 11:57:02 +0000 Subject: [PATCH] [MSVC] Handle out-of-line definition of static data member correctly (fix for http://llvm.org/PR21164), by Alexey Frolov MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are 3 cases of defining static const member: initialized inside the class, not defined outside the class. initialized inside the class, defined outside the class. not initialized inside the class, defined outside the class. Revision r213304 was supposed to fix the linkage problem of case (1), but mistakenly it made case (2) behave the same. As a result, out-of-line definition of static data member is not handled correctly. Proposed patch distinguishes between cases (1) and (2) and allows to properly emit static const members under –fms-compatibility option. This fixes http://llvm.org/PR21164. Differential Revision: http://reviews.llvm.org/D9850 llvm-svn: 237787 --- clang/lib/AST/ASTContext.cpp | 2 +- clang/test/CodeGenCXX/dllexport-members.cpp | 18 ++++-- .../ms-integer-static-data-members.cpp | 63 ++++++++++++------- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 770a2cf4df5e..4a831d90e645 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4931,7 +4931,7 @@ CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const { bool ASTContext::isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const { return getLangOpts().MSVCCompat && VD->isStaticDataMember() && VD->getType()->isIntegralOrEnumerationType() && - !VD->getFirstDecl()->isOutOfLine() && VD->getFirstDecl()->hasInit(); + VD->isFirstDecl() && !VD->isOutOfLine() && VD->hasInit(); } static inline diff --git a/clang/test/CodeGenCXX/dllexport-members.cpp b/clang/test/CodeGenCXX/dllexport-members.cpp index 5b2af1e04bd7..4038d0ba467d 100644 --- a/clang/test/CodeGenCXX/dllexport-members.cpp +++ b/clang/test/CodeGenCXX/dllexport-members.cpp @@ -110,9 +110,10 @@ public: // MSC-DAG: @"\01?StaticField@ExportMembers@@2HA" = dllexport global i32 1, align 4 // MSC-DAG: @"\01?StaticConstField@ExportMembers@@2HB" = dllexport constant i32 1, align 4 - // MSC-DAG: @"\01?StaticConstFieldEqualInit@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 - // MSC-DAG: @"\01?StaticConstFieldBraceInit@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 - // MSC-DAG: @"\01?ConstexprField@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?StaticConstFieldEqualInit@ExportMembers@@2HB" = dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?StaticConstFieldBraceInit@ExportMembers@@2HB" = dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?StaticConstFieldRefNotDef@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?ConstexprField@ExportMembers@@2HB" = dllexport constant i32 1, comdat, align 4 // GNU-DAG: @_ZN13ExportMembers11StaticFieldE = dllexport global i32 1, align 4 // GNU-DAG: @_ZN13ExportMembers16StaticConstFieldE = dllexport constant i32 1, align 4 // GNU-DAG: @_ZN13ExportMembers25StaticConstFieldEqualInitE = dllexport constant i32 1, align 4 @@ -122,6 +123,7 @@ public: __declspec(dllexport) static const int StaticConstField; __declspec(dllexport) static const int StaticConstFieldEqualInit = 1; __declspec(dllexport) static const int StaticConstFieldBraceInit{1}; + __declspec(dllexport) static const int StaticConstFieldRefNotDef = 1; __declspec(dllexport) constexpr static int ConstexprField = 1; }; @@ -144,6 +146,7 @@ inline void ExportMembers::staticInlineDef() {} const int ExportMembers::StaticConstField = 1; const int ExportMembers::StaticConstFieldEqualInit; const int ExportMembers::StaticConstFieldBraceInit; +int foo() { return ExportMembers::StaticConstFieldRefNotDef; } constexpr int ExportMembers::ConstexprField; @@ -233,9 +236,10 @@ public: // MSC-DAG: @"\01?StaticField@Nested@ExportMembers@@2HA" = dllexport global i32 1, align 4 // MSC-DAG: @"\01?StaticConstField@Nested@ExportMembers@@2HB" = dllexport constant i32 1, align 4 - // MSC-DAG: @"\01?StaticConstFieldEqualInit@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 - // MSC-DAG: @"\01?StaticConstFieldBraceInit@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 - // MSC-DAG: @"\01?ConstexprField@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?StaticConstFieldEqualInit@Nested@ExportMembers@@2HB" = dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?StaticConstFieldBraceInit@Nested@ExportMembers@@2HB" = dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?StaticConstFieldRefNotDef@Nested@ExportMembers@@2HB" = weak_odr dllexport constant i32 1, comdat, align 4 + // MSC-DAG: @"\01?ConstexprField@Nested@ExportMembers@@2HB" = dllexport constant i32 1, comdat, align 4 // GNU-DAG: @_ZN13ExportMembers6Nested11StaticFieldE = dllexport global i32 1, align 4 // GNU-DAG: @_ZN13ExportMembers6Nested16StaticConstFieldE = dllexport constant i32 1, align 4 // GNU-DAG: @_ZN13ExportMembers6Nested25StaticConstFieldEqualInitE = dllexport constant i32 1, align 4 @@ -245,6 +249,7 @@ public: __declspec(dllexport) static const int StaticConstField; __declspec(dllexport) static const int StaticConstFieldEqualInit = 1; __declspec(dllexport) static const int StaticConstFieldBraceInit{1}; + __declspec(dllexport) static const int StaticConstFieldRefNotDef = 1; __declspec(dllexport) constexpr static int ConstexprField = 1; }; @@ -267,6 +272,7 @@ inline void ExportMembers::Nested::staticInlineDef() {} const int ExportMembers::Nested::StaticConstField = 1; const int ExportMembers::Nested::StaticConstFieldEqualInit; const int ExportMembers::Nested::StaticConstFieldBraceInit; +int fooNested() { return ExportMembers::Nested::StaticConstFieldRefNotDef; } constexpr int ExportMembers::Nested::ConstexprField; diff --git a/clang/test/CodeGenCXX/ms-integer-static-data-members.cpp b/clang/test/CodeGenCXX/ms-integer-static-data-members.cpp index 4965f7319187..5e5b81d4a591 100644 --- a/clang/test/CodeGenCXX/ms-integer-static-data-members.cpp +++ b/clang/test/CodeGenCXX/ms-integer-static-data-members.cpp @@ -1,35 +1,52 @@ // RUN: %clang_cc1 -emit-llvm -triple=i386-pc-win32 -fms-compatibility %s -o - | FileCheck %s -// RUN: %clang_cc1 -DINLINE_INIT -emit-llvm -triple=i386-pc-win32 -fms-compatibility %s -o - | FileCheck %s --check-prefix=CHECK-INLINE -// RUN: %clang_cc1 -DREAL_DEFINITION -emit-llvm -triple=i386-pc-win32 -fms-compatibility %s -o - | FileCheck %s --check-prefix=CHECK-OUTOFLINE -// RUN: %clang_cc1 -DINLINE_INIT -DREAL_DEFINITION -emit-llvm -triple=i386-pc-win32 -fms-compatibility %s -o - | FileCheck %s --check-prefix=CHECK-INLINE struct S { - // For MS ABI, we emit a linkonce_odr definition here, even though it's really just a declaration. -#ifdef INLINE_INIT - static const int x = 5; -#else - static const int x; -#endif + static const int NoInit_Ref; + static const int Inline_NotDef_NotRef = 5; + static const int Inline_NotDef_Ref = 5; + static const int Inline_Def_NotRef = 5; + static const int Inline_Def_Ref = 5; + static const int OutOfLine_Def_NotRef; + static const int OutOfLine_Def_Ref; }; -const int *f() { - return &S::x; +const int *foo1() { + return &S::NoInit_Ref; }; -#ifdef REAL_DEFINITION -#ifdef INLINE_INIT -const int S::x; -#else -const int S::x = 5; -#endif -#endif +const int *foo2() { + return &S::Inline_NotDef_Ref; +}; +const int *foo3() { + return &S::Inline_Def_Ref; +}; -// Inline initialization. -// CHECK-INLINE: @"\01?x@S@@2HB" = linkonce_odr constant i32 5, comdat, align 4 +const int *foo4() { + return &S::OutOfLine_Def_Ref; +}; + +const int S::Inline_Def_NotRef; +const int S::Inline_Def_Ref; +const int S::OutOfLine_Def_NotRef = 5; +const int S::OutOfLine_Def_Ref = 5; -// Out-of-line initialization. -// CHECK-OUTOFLINE: @"\01?x@S@@2HB" = constant i32 5, align 4 // No initialization. -// CHECK: @"\01?x@S@@2HB" = external constant i32 +// CHECK-DAG: @"\01?NoInit_Ref@S@@2HB" = external constant i32 + +// Inline initialization, no real definiton, not referenced. +// CHECK-NOT: @"\01?Inline_NotDef_NotRef@S@@2HB" = {{.*}} constant i32 5 + +// Inline initialization, no real definiton, referenced. +// CHECK-DAG: @"\01?Inline_NotDef_Ref@S@@2HB" = linkonce_odr constant i32 5, comdat, align 4 + +// Inline initialization, real definiton, not referenced. +// CHECK-DAG: @"\01?Inline_Def_NotRef@S@@2HB" = constant i32 5, align 4 + +// Inline initialization, real definiton, referenced. +// CHECK-DAG: @"\01?Inline_Def_Ref@S@@2HB" = constant i32 5, comdat, align 4 + +// Out-of-line initialization. +// CHECK-DAG: @"\01?OutOfLine_Def_NotRef@S@@2HB" = constant i32 5, align 4 +// CHECK-DAG: @"\01?OutOfLine_Def_Ref@S@@2HB" = constant i32 5, align 4