From 6aa7df9df93bcf2d6399f6e535ef74c132db40ec Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 18 Sep 2013 01:35:26 +0000 Subject: [PATCH] If a variable template specialization with an incomplete array type is referenced, try to instantiate its definition in order to complete the type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190910 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Specifiers.h | 11 ++++- lib/Sema/SemaType.cpp | 40 ++++++++++--------- .../cxx1y-variable-templates_in_class.cpp | 36 +++++++++++++++-- 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 91383b76ba..b5e258bad4 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -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, diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index bce612a2a7..4cb4f5651f 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -4927,38 +4927,42 @@ bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser){ 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(E->IgnoreParens())) { if (VarDecl *Var = dyn_cast(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(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 diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index 1505481912..c878c13906 100644 --- a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -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 CONST T wrong; // expected-error {{member 'wrong' declared as a template}} template CONST T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}} @@ -179,9 +183,7 @@ namespace in_class_template { template static CONST U Data = U(100); }; template CONST int D3::Data; -#ifndef PRECXX11 static_assert(D3::Data == 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 struct S { template static int V; @@ -221,6 +223,34 @@ namespace in_class_template { template template int S::V = 123; int k = S::V; } + + namespace incomplete_array { + template extern T var[]; + template T var[] = { 1, 2, 3 }; + template<> char var[] = "hello"; + template char var[] = "pointer"; + + static_assert(sizeof(var) == 12, ""); + static_assert(sizeof(var) == 6, ""); + static_assert(sizeof(var) == 8, ""); + + template struct tuple; + + template struct A { + template static T x[]; + template static T y[]; + + template static T y >[]; + }; + + // FIXME: These cases should be accepted. + int *use_before_definition = A::x; + template template T A::x[sizeof(U)]; // expected-error {{forward declaration}} + static_assert(sizeof(A::x) == 1, ""); // expected-error {{incomplete}} + + template template T A::y >[] = { U()... }; + static_assert(sizeof(A::y >) == 12, ""); // expected-error {{incomplete}} + } } namespace in_nested_classes { -- 2.40.0