summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/ASTContext.cpp23
-rw-r--r--clang/test/CodeGenCXX/ms-constexpr-var-template.cpp11
2 files changed, 30 insertions, 4 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index dd88c919669..29a80f17eb9 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -9905,10 +9905,25 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
return StrongLinkage;
case TSK_ExplicitSpecialization:
- return Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- VD->isStaticDataMember()
- ? GVA_StrongODR
- : StrongLinkage;
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // If this is a fully specialized constexpr variable template, pretend it
+ // was marked inline. MSVC 14.21.27702 headers define _Is_integral in a
+ // header this way, and we don't want to emit non-discardable definitions
+ // of these variables in every TU that includes <type_traits>. This
+ // behavior is non-conforming, since another TU could use an extern
+ // template declaration for this variable, but for constexpr variables,
+ // it's unlikely for a user to want to do that. This behavior can be
+ // removed if the headers change to explicitly mark such variable template
+ // specializations inline.
+ if (isa<VarTemplateSpecializationDecl>(VD) && VD->isConstexpr())
+ return GVA_DiscardableODR;
+
+ // Use ODR linkage for static data members of fully specialized templates
+ // to prevent duplicate definition errors with MSVC.
+ if (VD->isStaticDataMember())
+ return GVA_StrongODR;
+ }
+ return StrongLinkage;
case TSK_ExplicitInstantiationDefinition:
return GVA_StrongODR;
diff --git a/clang/test/CodeGenCXX/ms-constexpr-var-template.cpp b/clang/test/CodeGenCXX/ms-constexpr-var-template.cpp
new file mode 100644
index 00000000000..a40f7aacac0
--- /dev/null
+++ b/clang/test/CodeGenCXX/ms-constexpr-var-template.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm -triple=x86_64-windows-msvc -fms-compatibility %s -o - | FileCheck %s
+
+template <typename> constexpr bool _Is_integer = false;
+template <> constexpr bool _Is_integer<int> = true;
+template <> constexpr bool _Is_integer<char> = false;
+extern "C" const bool *escape = &_Is_integer<int>;
+
+// CHECK: @"??$_Is_integer@H@@3_NB" = linkonce_odr dso_local constant i8 1, comdat, align 1
+// Should not emit _Is_integer<char>, since it's not referenced.
+// CHECK-NOT: @"??$_Is_integer@D@@3_NB"
+// CHECK: @escape = dso_local global i8* @"??$_Is_integer@H@@3_NB", align 8
OpenPOWER on IntegriCloud