]> granicus.if.org Git - clang/commitdiff
Don't suppress instantiation of definitions for variables subject to explicit
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 18 Oct 2017 22:45:01 +0000 (22:45 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 18 Oct 2017 22:45:01 +0000 (22:45 +0000)
instantiation declarations if they are usable from constant expressions.

We are permitted to instantiate in these cases, and required to do so in order
to have an initializer available for use within constant evaluation.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316136 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExpr.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CodeGenCXX/dllimport-members.cpp
test/SemaTemplate/cxx17-inline-variables.cpp [new file with mode: 0644]
test/SemaTemplate/extern-templates.cpp

index c92d0aa8f93e161d18aa734e76e4feb73117c9eb..1d8b9bc547cb908578cfae5fa4b550fc8be4669e 100644 (file)
@@ -14823,9 +14823,10 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
   TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
 
   bool OdrUseContext = isOdrUseContext(SemaRef);
+  bool UsableInConstantExpr =
+      Var->isUsableInConstantExpressions(SemaRef.Context);
   bool NeedDefinition =
-      OdrUseContext || (isEvaluatableContext(SemaRef) &&
-                        Var->isUsableInConstantExpressions(SemaRef.Context));
+      OdrUseContext || (isEvaluatableContext(SemaRef) && UsableInConstantExpr);
 
   VarTemplateSpecializationDecl *VarSpec =
       dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -14844,14 +14845,19 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
   // instantiations of variable templates, except for those that could be used
   // in a constant expression.
   if (NeedDefinition && isTemplateInstantiation(TSK)) {
-    bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
+    // Per C++17 [temp.explicit]p10, we may instantiate despite an explicit
+    // instantiation declaration if a variable is usable in a constant
+    // expression (among other cases).
+    bool TryInstantiating =
+        TSK == TSK_ImplicitInstantiation ||
+        (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr);
 
     if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) {
       if (Var->getPointOfInstantiation().isInvalid()) {
         // This is a modification of an existing AST node. Notify listeners.
         if (ASTMutationListener *L = SemaRef.getASTMutationListener())
           L->StaticDataMemberInstantiated(Var);
-      } else if (!Var->isUsableInConstantExpressions(SemaRef.Context))
+      } else if (!UsableInConstantExpr)
         // Don't bother trying to instantiate it again, unless we might need
         // its initializer before we get to the end of the TU.
         TryInstantiating = false;
@@ -14870,7 +14876,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
 
       // Do not instantiate specializations that are still type-dependent.
       if (IsNonDependent) {
-        if (Var->isUsableInConstantExpressions(SemaRef.Context)) {
+        if (UsableInConstantExpr) {
           // Do not defer instantiations of variables which could be used in a
           // constant expression.
           SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
index 3800ea6659b5257004a2b5fe506ffb23ed99bdfc..186a618387cc8c511b1c5c1bbfa36f2dedc7edaa 100644 (file)
@@ -4359,10 +4359,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
     return;
 
   // C++11 [temp.explicit]p10:
-  //   Except for inline functions, [...] explicit instantiation declarations
+  //   Except for inline functions, const variables of literal types, variables
+  //   of reference types, [...] explicit instantiation declarations
   //   have the effect of suppressing the implicit instantiation of the entity
   //   to which they refer.
-  if (TSK == TSK_ExplicitInstantiationDeclaration)
+  if (TSK == TSK_ExplicitInstantiationDeclaration &&
+      !Var->isUsableInConstantExpressions(getASTContext()))
     return;
 
   // Make sure to pass the instantiated variable to the consumer at the end.
index 19d9e1dfe7b6beb2236d898113e3c7d8119bc209..ff7868382d8c8e80e9dcecedbf4d97f696cb5e99 100644 (file)
@@ -836,7 +836,7 @@ USEMV(MemVarTmpl, ImportedStaticVar<ImplicitInst_Imported>)
 
 // Import explicit instantiation declaration of an imported member variable
 // template.
-// MSC-DAG: @"\01??$ImportedStaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = external dllimport constant i32
+// MSC-DAG: @"\01??$ImportedStaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = available_externally dllimport constant i32 1
 // GNU-DAG: @_ZN10MemVarTmpl17ImportedStaticVarI21ExplicitDecl_ImportedEE       = external dllimport constant i32
 extern template const int MemVarTmpl::ImportedStaticVar<ExplicitDecl_Imported>;
 USEMV(MemVarTmpl, ImportedStaticVar<ExplicitDecl_Imported>)
@@ -861,7 +861,7 @@ USEMV(MemVarTmpl, ImportedStaticVar<ExplicitSpec_NotImported>)
 
 // Import explicit instantiation declaration of a non-imported member variable
 // template.
-// MSC-DAG: @"\01??$StaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = external dllimport constant i32
+// MSC-DAG: @"\01??$StaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = available_externally dllimport constant i32 1
 // GNU-DAG: @_ZN10MemVarTmpl9StaticVarI21ExplicitDecl_ImportedEE        = external dllimport constant i32
 extern template __declspec(dllimport) const int MemVarTmpl::StaticVar<ExplicitDecl_Imported>;
 USEMV(MemVarTmpl, StaticVar<ExplicitDecl_Imported>)
diff --git a/test/SemaTemplate/cxx17-inline-variables.cpp b/test/SemaTemplate/cxx17-inline-variables.cpp
new file mode 100644 (file)
index 0000000..c018050
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// expected-no-diagnostics
+template<bool> struct DominatorTreeBase {
+  static constexpr bool IsPostDominator = true;
+};
+extern template class DominatorTreeBase<false>;
+constexpr bool k = DominatorTreeBase<false>::IsPostDominator;
index 5eb9c9db127c86cc3eba5df768be5eb4fd3e96c8..acbc9d57122efe1b8c9e823f2d8083c65c7669cb 100644 (file)
@@ -71,3 +71,10 @@ extern template void X1<const void*>::g(const void*);
 void g_X1_2(X1<const void *> x1, const void *ptr) {
   x1.g(ptr);
 }
+
+namespace static_const_member {
+  template <typename T> struct A { static const int n; };
+  template <typename T> const int A<T>::n = 3;
+  extern template struct A<int>;
+  int arr[A<int>::n];
+}