r190910 - If a variable template specialization with an incomplete array type is

Richard Smith richard-llvm at metafoo.co.uk
Tue Sep 17 18:35:26 PDT 2013


Author: rsmith
Date: Tue Sep 17 20:35:26 2013
New Revision: 190910

URL: http://llvm.org/viewvc/llvm-project?rev=190910&view=rev
Log:
If a variable template specialization with an incomplete array type is
referenced, try to instantiate its definition in order to complete the type.

Modified:
    cfe/trunk/include/clang/Basic/Specifiers.h
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp

Modified: cfe/trunk/include/clang/Basic/Specifiers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=190910&r1=190909&r2=190910&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Specifiers.h (original)
+++ cfe/trunk/include/clang/Basic/Specifiers.h Tue Sep 17 20:35:26 2013
@@ -131,8 +131,8 @@ namespace clang {
     OK_ObjCSubscript
   };
 
-  // \brief Describes the kind of template specialization that a
-  // particular template specialization declaration represents.
+  /// \brief Describes the kind of template specialization that a
+  /// particular template specialization declaration represents.
   enum TemplateSpecializationKind {
     /// This template specialization was formed from a template-id but
     /// has not yet been declared, defined, or instantiated.
@@ -154,6 +154,13 @@ namespace clang {
     TSK_ExplicitInstantiationDefinition
   };
 
+  /// \brief Determine whether this template specialization kind refers
+  /// to an instantiation of an entity (as opposed to a non-template or
+  /// an explicit specialization).
+  inline bool isTemplateInstantiation(TemplateSpecializationKind Kind) {
+    return Kind != TSK_Undeclared && Kind != TSK_ExplicitSpecialization;
+  }
+
   /// \brief Thread storage-class-specifier.
   enum ThreadStorageClassSpecifier {
     TSCS_unspecified,

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=190910&r1=190909&r2=190910&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Sep 17 20:35:26 2013
@@ -4927,38 +4927,42 @@ bool Sema::RequireCompleteExprType(Expr
     return false;
 
   // Incomplete array types may be completed by the initializer attached to
-  // their definitions. For static data members of class templates we need to
-  // instantiate the definition to get this initializer and complete the type.
+  // their definitions. For static data members of class templates and for
+  // variable templates, we need to instantiate the definition to get this
+  // initializer and complete the type.
   if (T->isIncompleteArrayType()) {
     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
       if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
-        if (Var->isStaticDataMember() &&
-            Var->getInstantiatedFromStaticDataMember()) {
+        if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) {
+          SourceLocation PointOfInstantiation = E->getExprLoc();
 
-          MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
-          assert(MSInfo && "Missing member specialization information?");
-          if (MSInfo->getTemplateSpecializationKind()
-                != TSK_ExplicitSpecialization) {
+          if (MemberSpecializationInfo *MSInfo =
+                  Var->getMemberSpecializationInfo()) {
             // If we don't already have a point of instantiation, this is it.
             if (MSInfo->getPointOfInstantiation().isInvalid()) {
-              MSInfo->setPointOfInstantiation(E->getLocStart());
+              MSInfo->setPointOfInstantiation(PointOfInstantiation);
 
               // This is a modification of an existing AST node. Notify
               // listeners.
               if (ASTMutationListener *L = getASTMutationListener())
                 L->StaticDataMemberInstantiated(Var);
             }
+          } else {
+            VarTemplateSpecializationDecl *VarSpec =
+                cast<VarTemplateSpecializationDecl>(Var);
+            if (VarSpec->getPointOfInstantiation().isInvalid())
+              VarSpec->setPointOfInstantiation(PointOfInstantiation);
+          }
 
-            InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var);
+          InstantiateVariableDefinition(PointOfInstantiation, Var);
 
-            // Update the type to the newly instantiated definition's type both
-            // here and within the expression.
-            if (VarDecl *Def = Var->getDefinition()) {
-              DRE->setDecl(Def);
-              T = Def->getType();
-              DRE->setType(T);
-              E->setType(T);
-            }
+          // Update the type to the newly instantiated definition's type both
+          // here and within the expression.
+          if (VarDecl *Def = Var->getDefinition()) {
+            DRE->setDecl(Def);
+            T = Def->getType();
+            DRE->setType(T);
+            E->setType(T);
           }
 
           // We still go on to try to complete the type independently, as it

Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp?rev=190910&r1=190909&r2=190910&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Tue Sep 17 20:35:26 2013
@@ -4,6 +4,10 @@
 
 #define CONST const
 
+#ifdef PRECXX11
+#define static_assert(expr, msg) typedef int static_assert[(expr) ? 1 : -1];
+#endif
+
 class A {
   template<typename T> CONST T wrong;           // expected-error {{member 'wrong' declared as a template}}
   template<typename T> CONST T wrong_init = 5;      // expected-error {{member 'wrong_init' declared as a template}}
@@ -179,9 +183,7 @@ namespace in_class_template {
     template<typename U> static CONST U Data = U(100);
   };
   template CONST int D3<float>::Data<int>;
-#ifndef PRECXX11
   static_assert(D3<float>::Data<int> == 100, "");
-#endif
 
   namespace bug_files {
     // FIXME: A bug has been filed addressing an issue similar to these.
@@ -210,7 +212,7 @@ namespace in_class_template {
   }
   
   namespace other_bugs {
-    // FIXME: This fails to properly initilize the variable 'k'.
+    // FIXME: This fails to properly initialize the variable 'k'.
     
     template<typename A> struct S { 
       template<typename B> static int V;
@@ -221,6 +223,34 @@ namespace in_class_template {
     template<typename A> template<typename B> int S<A>::V<B> = 123;
     int k = S<int>::V<void>;
   }
+
+  namespace incomplete_array {
+    template<typename T> extern T var[];
+    template<typename T> T var[] = { 1, 2, 3 };
+    template<> char var<char>[] = "hello";
+    template<typename T> char var<T*>[] = "pointer";
+
+    static_assert(sizeof(var<int>) == 12, "");
+    static_assert(sizeof(var<char>) == 6, "");
+    static_assert(sizeof(var<void*>) == 8, "");
+
+    template<typename...> struct tuple;
+
+    template<typename T> struct A {
+      template<typename U> static T x[];
+      template<typename U> static T y[];
+
+      template<typename...U> static T y<tuple<U...> >[];
+    };
+
+    // FIXME: These cases should be accepted.
+    int *use_before_definition = A<int>::x<char>;
+    template<typename T> template<typename U> T A<T>::x<U>[sizeof(U)]; // expected-error {{forward declaration}}
+    static_assert(sizeof(A<int>::x<char>) == 1, ""); // expected-error {{incomplete}}
+
+    template<typename T> template<typename...U> T A<T>::y<tuple<U...> >[] = { U()... };
+    static_assert(sizeof(A<int>::y<tuple<char, char, char> >) == 12, ""); // expected-error {{incomplete}}
+  }
 }
 
 namespace in_nested_classes {





More information about the cfe-commits mailing list