sepavloff created this revision. sepavloff added reviewers: rsmith, tra. sepavloff added a subscriber: cfe-commits.
Current version of clang cannot build the program: ``` template<int n> int var; int main(int argc, char *argv[]) { return var<0>; } ``` as linker does not find `var<0>`, codegen treats it as declaration only. However this program must build succesfully, because the template declaration is a definition as none of the conditions mentioned in [basic.def]p2 is met. With this change codegen generates definitions for file level variable template specialization even if the declaration does not contain an initializer. https://reviews.llvm.org/D24649 Files: lib/CodeGen/CodeGenModule.cpp test/CodeGenCXX/dllexport.cpp test/CodeGenCXX/variable-templates.cpp Index: test/CodeGenCXX/variable-templates.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/variable-templates.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -std=c++14 %s -triple=x86_64-linux -emit-llvm -o - | FileCheck %s + +// Unused template +// CHECK-NOT: _Z6var_00ILi0EE +template<int n> int var_00; + +// Definition without initializer +// CHECK: @_Z6var_01ILi0EE = linkonce_odr global i32 0, comdat +template<int n> int var_01; +int use_01a() { + return var_01<0>; +} +int use_01b() { + return var_01<0>; +} + +// Definitions without initializer combined with extern declaration + +// CHECK: @_Z6var_02ILi0EE = linkonce_odr global i32 0, comdat +template<int n> extern int var_02; +template<int n> int var_02; +int use_02() { + return var_02<0>; +} + +// CHECK: @_Z6var_03ILi0EE = linkonce_odr global i32 0, comdat +template<int n> int var_03; +template<int n> extern int var_03; +int use_03() { + return var_03<0>; +} + +// CHECK: @_Z6var_04ILi0EE = linkonce_odr global i32 0, comdat +template<int n> extern int var_04; +int use_04() { + return var_04<0>; +} +template<int n> int var_04; + +// CHECK: @_Z6var_05ILi0EE = linkonce_odr global i32 0, comdat +template<int n> int var_05; +int use_05() { + return var_05<0>; +} +template<int n> extern int var_05; + + +int main(int argc, char *argv[]) { + return 0; +} Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -108,8 +108,8 @@ template<typename T> __declspec(dllexport) int VarTmplDef; INSTVAR(VarTmplDef<ExplicitInst_Exported>) -// MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = external dllexport global -// GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = external dllexport global +// MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global +// GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = weak_odr dllexport global template<typename T> __declspec(dllexport) int VarTmplImplicitDef; USEVAR(VarTmplImplicitDef<ImplicitInst_Exported>) Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1609,7 +1609,11 @@ !VD->hasDefinition() && (VD->hasAttr<CUDAConstantAttr>() || VD->hasAttr<CUDADeviceAttr>()); - if (!MustEmitForCuda && + bool MustEmitVarInst = isa<VarTemplateSpecializationDecl>(VD) && + !VD->isStaticDataMember() && + !VD->hasDefinition() && + !VD->hasAttr<DLLImportAttr>(); + if (!(MustEmitForCuda || MustEmitVarInst) && VD->isThisDeclarationADefinition() != VarDecl::Definition && !Context.isMSStaticDataMemberInlineDefinition(VD)) { // If this declaration may have caused an inline variable definition to
Index: test/CodeGenCXX/variable-templates.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/variable-templates.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -std=c++14 %s -triple=x86_64-linux -emit-llvm -o - | FileCheck %s + +// Unused template +// CHECK-NOT: _Z6var_00ILi0EE +template<int n> int var_00; + +// Definition without initializer +// CHECK: @_Z6var_01ILi0EE = linkonce_odr global i32 0, comdat +template<int n> int var_01; +int use_01a() { + return var_01<0>; +} +int use_01b() { + return var_01<0>; +} + +// Definitions without initializer combined with extern declaration + +// CHECK: @_Z6var_02ILi0EE = linkonce_odr global i32 0, comdat +template<int n> extern int var_02; +template<int n> int var_02; +int use_02() { + return var_02<0>; +} + +// CHECK: @_Z6var_03ILi0EE = linkonce_odr global i32 0, comdat +template<int n> int var_03; +template<int n> extern int var_03; +int use_03() { + return var_03<0>; +} + +// CHECK: @_Z6var_04ILi0EE = linkonce_odr global i32 0, comdat +template<int n> extern int var_04; +int use_04() { + return var_04<0>; +} +template<int n> int var_04; + +// CHECK: @_Z6var_05ILi0EE = linkonce_odr global i32 0, comdat +template<int n> int var_05; +int use_05() { + return var_05<0>; +} +template<int n> extern int var_05; + + +int main(int argc, char *argv[]) { + return 0; +} Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -108,8 +108,8 @@ template<typename T> __declspec(dllexport) int VarTmplDef; INSTVAR(VarTmplDef<ExplicitInst_Exported>) -// MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = external dllexport global -// GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = external dllexport global +// MSC-DAG: @"\01??$VarTmplImplicitDef@UImplicitInst_Exported@@@@3HA" = weak_odr dllexport global +// GNU-DAG: @_Z18VarTmplImplicitDefI21ImplicitInst_ExportedE = weak_odr dllexport global template<typename T> __declspec(dllexport) int VarTmplImplicitDef; USEVAR(VarTmplImplicitDef<ImplicitInst_Exported>) Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1609,7 +1609,11 @@ !VD->hasDefinition() && (VD->hasAttr<CUDAConstantAttr>() || VD->hasAttr<CUDADeviceAttr>()); - if (!MustEmitForCuda && + bool MustEmitVarInst = isa<VarTemplateSpecializationDecl>(VD) && + !VD->isStaticDataMember() && + !VD->hasDefinition() && + !VD->hasAttr<DLLImportAttr>(); + if (!(MustEmitForCuda || MustEmitVarInst) && VD->isThisDeclarationADefinition() != VarDecl::Definition && !Context.isMSStaticDataMemberInlineDefinition(VD)) { // If this declaration may have caused an inline variable definition to
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits