erichkeane created this revision. erichkeane added reviewers: rnk, rjmccall, majnemer.
MSVC's type_trait header for the 16.3.* release in pre-c++17 mode exposes explicitly specialized constexpr variables for _Is_integral, is_void_v, and _Is_floating_point as not-inline (since that isn't available in pre-C++17). The result is duplicate-symbols in any program that includes <type_traits> more than once. This patch works around this issue by making fairly specific cases (in the system header, in MSVC mode, and in pre-c++17 mode) be weak_odr linkage rather than External linkage. https://reviews.llvm.org/D70791 Files: clang/lib/AST/ASTContext.cpp clang/test/CodeGenCXX/Inputs/ms-constexpr-typetraits.h clang/test/CodeGenCXX/microsoft-type-traits-pre-cxx17.cpp Index: clang/test/CodeGenCXX/microsoft-type-traits-pre-cxx17.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/microsoft-type-traits-pre-cxx17.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -std=c++14 -o - %s -isystem%S/Inputs | FileCheck %s +#include <ms-constexpr-typetraits.h> + +// CHECK: @"??$_Is_integral@_N@@3_NB" = weak_odr dso_local constant +// CHECK: @"??$_Is_floating_point@M@@3_NB" = weak_odr dso_local constant +// CHECK: @"??$is_void_v@X@@3_NB" = weak_odr dso_local constant + Index: clang/test/CodeGenCXX/Inputs/ms-constexpr-typetraits.h =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/Inputs/ms-constexpr-typetraits.h @@ -0,0 +1,17 @@ +template <class> +constexpr bool _Is_integral = false; + +template <> +constexpr bool _Is_integral<bool> = true; + +template <class> +constexpr bool _Is_floating_point = false; + +template <> +constexpr bool _Is_floating_point<float> = true; + +template <class> +constexpr bool is_void_v = false; + +template <> +constexpr bool is_void_v<void> = true; Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -9860,6 +9860,19 @@ return L; } +// The MSVC type_traits header defines a handful of type-trait constexpr +// variables as non-inline in pre-C++17 mode which causes duplicate symbols. +// In C++17 cases, they mark these as 'inline', which avoids this issue. +// This fixup alters the linkage to be odr for this case. +static bool isMSVCPreCxx17TypeTrait(const ASTContext &Context, + const VarDecl *VD) { + assert(VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + "Only valid for explicit specializations"); + return VD->isConstexpr() && !VD->isInline() && + !Context.getLangOpts().CPlusPlus17 && + Context.getSourceManager().isInSystemHeader(VD->getLocation()); +} + GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { return adjustGVALinkageForExternalDefinitionKind(*this, FD, adjustGVALinkageForAttributes(*this, FD, @@ -9926,7 +9939,8 @@ case TSK_ExplicitSpecialization: return Context.getTargetInfo().getCXXABI().isMicrosoft() && - VD->isStaticDataMember() + (VD->isStaticDataMember() || + isMSVCPreCxx17TypeTrait(Context, VD)) ? GVA_StrongODR : StrongLinkage;
Index: clang/test/CodeGenCXX/microsoft-type-traits-pre-cxx17.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/microsoft-type-traits-pre-cxx17.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -std=c++14 -o - %s -isystem%S/Inputs | FileCheck %s +#include <ms-constexpr-typetraits.h> + +// CHECK: @"??$_Is_integral@_N@@3_NB" = weak_odr dso_local constant +// CHECK: @"??$_Is_floating_point@M@@3_NB" = weak_odr dso_local constant +// CHECK: @"??$is_void_v@X@@3_NB" = weak_odr dso_local constant + Index: clang/test/CodeGenCXX/Inputs/ms-constexpr-typetraits.h =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/Inputs/ms-constexpr-typetraits.h @@ -0,0 +1,17 @@ +template <class> +constexpr bool _Is_integral = false; + +template <> +constexpr bool _Is_integral<bool> = true; + +template <class> +constexpr bool _Is_floating_point = false; + +template <> +constexpr bool _Is_floating_point<float> = true; + +template <class> +constexpr bool is_void_v = false; + +template <> +constexpr bool is_void_v<void> = true; Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -9860,6 +9860,19 @@ return L; } +// The MSVC type_traits header defines a handful of type-trait constexpr +// variables as non-inline in pre-C++17 mode which causes duplicate symbols. +// In C++17 cases, they mark these as 'inline', which avoids this issue. +// This fixup alters the linkage to be odr for this case. +static bool isMSVCPreCxx17TypeTrait(const ASTContext &Context, + const VarDecl *VD) { + assert(VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + "Only valid for explicit specializations"); + return VD->isConstexpr() && !VD->isInline() && + !Context.getLangOpts().CPlusPlus17 && + Context.getSourceManager().isInSystemHeader(VD->getLocation()); +} + GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { return adjustGVALinkageForExternalDefinitionKind(*this, FD, adjustGVALinkageForAttributes(*this, FD, @@ -9926,7 +9939,8 @@ case TSK_ExplicitSpecialization: return Context.getTargetInfo().getCXXABI().isMicrosoft() && - VD->isStaticDataMember() + (VD->isStaticDataMember() || + isMSVCPreCxx17TypeTrait(Context, VD)) ? GVA_StrongODR : StrongLinkage;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits