Closed by commit rL213304 (authored by @hans).
REPOSITORY
rL LLVM
http://reviews.llvm.org/D4563
Files:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/CodeGen/CGCXXABI.h
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
cfe/trunk/lib/CodeGen/ModuleBuilder.cpp
cfe/trunk/test/CodeGenCXX/dllexport-members.cpp
cfe/trunk/test/CodeGenCXX/dllimport-members.cpp
cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp
cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members.cpp
Index: cfe/trunk/lib/CodeGen/CGCXXABI.h
===================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h
@@ -403,10 +403,6 @@
/// Gets the deleted virtual member call name.
virtual StringRef GetDeletedVirtualCallName() = 0;
- /// \brief Returns true iff static data members that are initialized in the
- /// class definition should have linkonce linkage.
- virtual bool isInlineInitializedStaticDataMemberLinkOnce() { return false; }
-
/**************************** Array cookies ******************************/
/// Returns the extra size required in order to store the array
Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp
@@ -1256,7 +1256,8 @@
const auto *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- if (VD->isThisDeclarationADefinition() != VarDecl::Definition)
+ if (VD->isThisDeclarationADefinition() != VarDecl::Definition &&
+ !Context.isMSStaticDataMemberInlineDefinition(VD))
return;
}
@@ -1592,18 +1593,6 @@
return true;
}
-static bool isVarDeclInlineInitializedStaticDataMember(const VarDecl *VD) {
- if (!VD->isStaticDataMember())
- return false;
- const VarDecl *InitDecl;
- const Expr *InitExpr = VD->getAnyInitializer(InitDecl);
- if (!InitExpr)
- return false;
- if (InitDecl->isThisDeclarationADefinition())
- return false;
- return true;
-}
-
/// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module,
/// create and return an llvm GlobalVariable with the specified type. If there
/// is something in the module with the specified name, return it potentially
@@ -1666,9 +1655,9 @@
// If required by the ABI, treat declarations of static data members with
// inline initializers as definitions.
- if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
- isVarDeclInlineInitializedStaticDataMember(D))
+ if (getContext().isMSStaticDataMemberInlineDefinition(D)) {
EmitGlobalVarDefinition(D);
+ }
// Handle XCore specific ABI requirements.
if (getTarget().getTriple().getArch() == llvm::Triple::xcore &&
@@ -2087,18 +2076,6 @@
return !Context.getLangOpts().AppleKext ? llvm::Function::WeakODRLinkage
: llvm::Function::ExternalLinkage;
- // If required by the ABI, give definitions of static data members with inline
- // initializers at least linkonce_odr linkage.
- auto const VD = dyn_cast<VarDecl>(D);
- if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
- VD && isVarDeclInlineInitializedStaticDataMember(VD)) {
- if (VD->hasAttr<DLLImportAttr>())
- return llvm::GlobalValue::AvailableExternallyLinkage;
- if (VD->hasAttr<DLLExportAttr>())
- return llvm::GlobalValue::WeakODRLinkage;
- return llvm::GlobalValue::LinkOnceODRLinkage;
- }
-
// C++ doesn't have tentative definitions and thus cannot have common
// linkage.
if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
Index: cfe/trunk/lib/CodeGen/ModuleBuilder.cpp
===================================================================
--- cfe/trunk/lib/CodeGen/ModuleBuilder.cpp
+++ cfe/trunk/lib/CodeGen/ModuleBuilder.cpp
@@ -128,6 +128,19 @@
return;
Builder->UpdateCompletedType(D);
+
+ // For MSVC compatibility, treat declarations of static data members with
+ // inline initializers as definitions.
+ if (Ctx->getLangOpts().MSVCCompat) {
+ for (Decl *Member : D->decls()) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(Member)) {
+ if (Ctx->isMSStaticDataMemberInlineDefinition(VD) &&
+ Ctx->DeclMustBeEmitted(VD)) {
+ Builder->EmitGlobal(VD);
+ }
+ }
+ }
+ }
}
void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
Index: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -55,8 +55,6 @@
// arbitrary.
StringRef GetDeletedVirtualCallName() override { return "_purecall"; }
- bool isInlineInitializedStaticDataMemberLinkOnce() override { return true; }
-
llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
llvm::Value *ptr,
QualType type) override;
Index: cfe/trunk/lib/AST/ASTContext.cpp
===================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp
+++ cfe/trunk/lib/AST/ASTContext.cpp
@@ -4781,6 +4781,12 @@
return sz;
}
+bool ASTContext::isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const {
+ return getLangOpts().MSVCCompat && VD->isStaticDataMember() &&
+ VD->getType()->isIntegralOrEnumerationType() &&
+ !VD->getFirstDecl()->isOutOfLine() && VD->getFirstDecl()->hasInit();
+}
+
static inline
std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
@@ -7849,6 +7855,12 @@
: StaticLocalLinkage;
}
+ // MSVC treats in-class initialized static data members as definitions.
+ // By giving them non-strong linkage, out-of-line definitions won't
+ // cause link errors.
+ if (Context.isMSStaticDataMemberInlineDefinition(VD))
+ return GVA_DiscardableODR;
+
switch (VD->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
@@ -7934,7 +7946,8 @@
const VarDecl *VD = cast<VarDecl>(D);
assert(VD->isFileVarDecl() && "Expected file scoped var");
- if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly)
+ if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly &&
+ !isMSStaticDataMemberInlineDefinition(VD))
return false;
// Variables that can be needed in other TUs are required.
Index: cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp
===================================================================
--- cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp
+++ cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members-exported.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm -triple=i386-pc-win32 -fms-compatibility %s -o - | FileCheck %s
+
+enum Enum { zero, one, two };
+
+struct __declspec(dllexport) S {
+ // In MS compatibility mode, this counts as a definition.
+ // Since it is exported, it must be emitted even if it's unreferenced.
+ static const short x = 42;
+
+ // This works for enums too.
+ static const Enum y = two;
+
+ struct NonExported {
+ // dllexport is not inherited by this nested class.
+ // Since z is not referenced, it should not be emitted.
+ static const int z = 42;
+ };
+};
+
+// CHECK: @"\01?x@S@@2FB" = weak_odr dllexport constant i16 42, align 2
+// CHECK: @"\01?y@S@@2W4Enum@@B" = weak_odr dllexport constant i32 2, align 4
+// CHECK-NOT: NonExported
Index: cfe/trunk/test/CodeGenCXX/dllimport-members.cpp
===================================================================
--- cfe/trunk/test/CodeGenCXX/dllimport-members.cpp
+++ cfe/trunk/test/CodeGenCXX/dllimport-members.cpp
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M64 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G64 %s
-// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O1 -o - %s -DMSABI | FileCheck --check-prefix=MO1 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O1 -o - %s | FileCheck --check-prefix=GO1 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -fms-compatibility -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M64 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G64 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -fms-compatibility -emit-llvm -std=c++1y -O1 -o - %s -DMSABI | FileCheck --check-prefix=MO1 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O1 -o - %s | FileCheck --check-prefix=GO1 %s
// Helper structs to make templates more expressive.
struct ImplicitInst_Imported {};
Index: cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members.cpp
===================================================================
--- cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members.cpp
+++ cfe/trunk/test/CodeGenCXX/ms-integer-static-data-members.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s
-// RUN: %clang_cc1 -DINLINE_INIT -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-INLINE
-// RUN: %clang_cc1 -DREAL_DEFINITION -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-OUTOFLINE
-// RUN: %clang_cc1 -DINLINE_INIT -DREAL_DEFINITION -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK-INLINE
+// 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.
Index: cfe/trunk/test/CodeGenCXX/dllexport-members.cpp
===================================================================
--- cfe/trunk/test/CodeGenCXX/dllexport-members.cpp
+++ cfe/trunk/test/CodeGenCXX/dllexport-members.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=MSC --check-prefix=M32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=MSC --check-prefix=M64 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G64 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc -fms-compatibility -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=MSC --check-prefix=M32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=MSC --check-prefix=M64 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G64 %s
// Helper structs to make templates more expressive.
struct ImplicitInst_Exported {};
Index: cfe/trunk/include/clang/AST/ASTContext.h
===================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h
+++ cfe/trunk/include/clang/AST/ASTContext.h
@@ -2283,6 +2283,10 @@
void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
QualType T, std::string& S,
bool Extended) const;
+
+ /// \brief Returns true if this is an inline-initialized static data member
+ /// which is treated as a definition for MSVC compatibility.
+ bool isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const;
private:
const ASTRecordLayout &
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits