If a variable template specialization with an incomplete array type is

referenced, try to instantiate its definition in order to complete the type.

llvm-svn: 190910
This commit is contained in:
Richard Smith 2013-09-18 01:35:26 +00:00
parent e693e8432e
commit 785067eca7
3 changed files with 64 additions and 23 deletions

View File

@ -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,

View File

@ -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<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

View File

@ -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 {