forked from OSchip/llvm-project
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:
parent
e693e8432e
commit
785067eca7
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue