zoecarver created this revision.
zoecarver added a reviewer: rsmith.
zoecarver requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Because MSVC will not treat the definition of a static data member as part of 
the declaration, it will not get instantiated. This means Clang won't diagnose 
instantiation errors until the data member itself is used.

Note: this only happens for constexpr data members because they are the only 
ones that are marked as implicitly inline and therefore not part of the 
declaration.

Refs: https://llvm.org/PR49618
Refs: https://github.com/apple/swift/pull/35962


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D98904

Files:
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/windows-data-member-instantiation-errors.cpp


Index: clang/test/SemaCXX/windows-data-member-instantiation-errors.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/windows-data-member-instantiation-errors.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -verify -std=c++17 %s
+
+template <class T>
+struct GetTypeValue {
+  // expected-error@+1{{type 'int' cannot be used prior to '::' because it has 
no members}}
+  static constexpr const bool value = T::value;
+};
+
+using Invalid = GetTypeValue<int>;
+
+// expected-note@+1{{in instantiation of template class 'GetTypeValue<int>' 
requested here}}
+void test(Invalid) {}
+
+// expected-note@+2{{candidate constructor (the implicit copy constructor) not 
viable: no known conversion from 'int' to 'const S &' for 1st argument}}
+// expected-note@+1{{candidate constructor (the implicit move constructor) not 
viable: no known conversion from 'int' to 'S &&' for 1st argument}}
+struct S {};
+
+template <class T>
+struct MakeS {
+  // expected-error@+1{{no viable conversion from 'int' to 'const S'}}
+  static constexpr const S value = T();
+};
+
+using Invalid2 = MakeS<int>;
+
+// expected-note@+1{{in instantiation of template class 'MakeS<int>' requested 
here}}
+void test2(Invalid2) {}
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5111,7 +5111,11 @@
     InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
   } else if (InstantiatingSpecFromTemplate ||
              (OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
-              !NewVar->isThisDeclarationADefinition())) {
+              !NewVar->isThisDeclarationADefinition() &&
+              // On Microsoft's ABI, the new var's initializer will be part of
+              // the definition. But, we still want to instanciate it so that
+              // we can catch instantiation errors.
+              !Context.getTargetInfo().getCXXABI().isMicrosoft())) {
     // Delay instantiation of the initializer for variable template
     // specializations or inline static data members until a definition of the
     // variable is needed.


Index: clang/test/SemaCXX/windows-data-member-instantiation-errors.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/windows-data-member-instantiation-errors.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -verify -std=c++17 %s
+
+template <class T>
+struct GetTypeValue {
+  // expected-error@+1{{type 'int' cannot be used prior to '::' because it has no members}}
+  static constexpr const bool value = T::value;
+};
+
+using Invalid = GetTypeValue<int>;
+
+// expected-note@+1{{in instantiation of template class 'GetTypeValue<int>' requested here}}
+void test(Invalid) {}
+
+// expected-note@+2{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const S &' for 1st argument}}
+// expected-note@+1{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'S &&' for 1st argument}}
+struct S {};
+
+template <class T>
+struct MakeS {
+  // expected-error@+1{{no viable conversion from 'int' to 'const S'}}
+  static constexpr const S value = T();
+};
+
+using Invalid2 = MakeS<int>;
+
+// expected-note@+1{{in instantiation of template class 'MakeS<int>' requested here}}
+void test2(Invalid2) {}
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5111,7 +5111,11 @@
     InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
   } else if (InstantiatingSpecFromTemplate ||
              (OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
-              !NewVar->isThisDeclarationADefinition())) {
+              !NewVar->isThisDeclarationADefinition() &&
+              // On Microsoft's ABI, the new var's initializer will be part of
+              // the definition. But, we still want to instanciate it so that
+              // we can catch instantiation errors.
+              !Context.getTargetInfo().getCXXABI().isMicrosoft())) {
     // Delay instantiation of the initializer for variable template
     // specializations or inline static data members until a definition of the
     // variable is needed.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D98904: I... Zoe Carver via Phabricator via cfe-commits

Reply via email to