Implement explicit instantiations of member classes of class templates, e.g.,

template<typename T>
  struct X {
    struct Inner;
  };

  template struct X<int>::Inner;

This change is larger than it looks because it also fixes some
a problem with nested-name-specifiers and tags. We weren't requiring
the DeclContext associated with the scope specifier of a tag to be
complete. Therefore, when looking for something like "struct
X<int>::Inner", we weren't instantiating X<int>. 

This, naturally, uncovered a problem with member pointers, where we
were requiring the left-hand side of a member pointer access
expression (e.g., x->*) to be a complete type. However, this is wrong:
the semantics of this expression does not require a complete type (EDG
agrees).

Stuart vouched for me. Blame him.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71756 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-05-14 00:28:11 +00:00
Родитель 88f1ba0f04
Коммит 3f5b61c394
15 изменённых файлов: 231 добавлений и 28 удалений

Просмотреть файл

@ -737,6 +737,14 @@ def ext_explicit_instantiation_after_specialization : Extension<
"specialization will be ignored (C++0x extension)">;
def note_previous_template_specialization : Note<
"previous template specialization is here">;
def err_explicit_instantiation_enum : Error<
"explicit instantiation of enumeration type %0">;
def err_explicit_instantiation_nontemplate_type : Error<
"explicit instantiation of non-templated type %0">;
def note_nontemplate_decl_here : Note<
"non-templated declaration is here">;
def err_explicit_instantiation_out_of_scope : Error<
"explicit instantiation of %0 not in a namespace enclosing %1">;
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
@ -1234,8 +1242,6 @@ def err_qualified_catch_declarator : Error<
def err_early_catch_all : Error<"catch-all handler must come last">;
def err_bad_memptr_rhs : Error<
"right hand operand to %0 has non pointer-to-member type %1">;
def err_memptr_rhs_incomplete : Error<
"right hand operand is a pointer to member of incomplete type %0">;
def err_bad_memptr_lhs : Error<
"left hand operand to %0 must be a %select{|pointer to }1class "
"compatible with the right hand operand, but is %2">;

Просмотреть файл

@ -1373,7 +1373,56 @@ public:
return DeclResult();
}
/// \brief Process the explicit instantiation of a member class of a
/// class template specialization.
///
/// This routine is invoked when an explicit instantiation of a
/// member class of a class template specialization is
/// encountered. In the following example,
/// ActOnExplicitInstantiation will be invoked to force the
/// instantiation of X<int>::Inner:
///
/// \code
/// template<typename T> class X { class Inner { /* ... */}; };
/// template class X<int>::Inner; // explicit instantiation
/// \endcode
///
/// \param S the current scope
///
/// \param TemplateLoc the location of the 'template' keyword that
/// specifies that this is an explicit instantiation.
///
/// \param TagSpec whether this declares a class, struct, or union
/// (template).
///
/// \param KWLoc the location of the 'class', 'struct', or 'union'
/// keyword.
///
/// \param SS the scope specifier preceding the template-id.
///
/// \param Template the declaration of the class template that we
/// are instantiation.
///
/// \param LAngleLoc the location of the '<' token in the template-id.
///
/// \param TemplateArgs the template arguments used to form the
/// template-id.
///
/// \param TemplateArgLocs the locations of the template arguments.
///
/// \param RAngleLoc the location of the '>' token in the template-id.
///
/// \param Attr attributes that apply to this instantiation.
virtual DeclResult
ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr) {
return DeclResult();
}
/// \brief Called when the parser has parsed a C++ typename
/// specifier that ends in an identifier, e.g., "typename T::type".

Просмотреть файл

@ -560,7 +560,7 @@ private:
TemplateParams(TemplateParams) { }
explicit ParsedTemplateInfo(SourceLocation TemplateLoc)
: Kind(ExplicitInstantiation),
: Kind(ExplicitInstantiation), TemplateParams(0),
TemplateLoc(TemplateLoc) { }
/// \brief The kind of template we are parsing.

Просмотреть файл

@ -514,10 +514,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
//
// template class Foo<X>
//
// but it is actually a declaration. Most likely, this was
// but it actually has a definition. Most likely, this was
// meant to be an explicit specialization, but the user forgot
// the '<>' after 'template'.
assert(TK == Action::TK_Definition && "Can only get a definition here");
assert(TK == Action::TK_Definition && "Expected a definition here");
SourceLocation LAngleLoc
= PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
@ -554,7 +554,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParams? TemplateParams->size() : 0));
}
TemplateId->Destroy();
} else if (TemplateParams && TK != Action::TK_Reference)
} else if (TemplateParams && TK != Action::TK_Reference) {
// Class template declaration or definition.
TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK,
StartLoc, SS, Name, NameLoc,
Attr,
@ -562,9 +563,28 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
&(*TemplateParams)[0],
TemplateParams->size()),
AS);
else
TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name,
NameLoc, Attr, AS);
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TK == Action::TK_Declaration) {
// Explicit instantiation of a member of a class template
// specialization, e.g.,
//
// template struct Outer<int>::Inner;
//
TagOrTempResult
= Actions.ActOnExplicitInstantiation(CurScope,
TemplateInfo.TemplateLoc,
TagType, StartLoc, SS, Name,
NameLoc, Attr);
} else {
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TK == Action::TK_Definition) {
// FIXME: Diagnose this particular error.
}
// Declaration or definition of a class type
TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS,
Name, NameLoc, Attr, AS);
}
// Parse the optional base clause (C++ only).
if (getLang().CPlusPlus && Tok.is(tok::colon))

Просмотреть файл

@ -149,7 +149,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType(&SS);
SS.clear();
SS.setScopeRep(0);
assert(Tok.is(tok::annot_typename) &&
"AnnotateTemplateIdTokenAsType isn't working");

Просмотреть файл

@ -1919,6 +1919,15 @@ public:
SourceLocation RAngleLoc,
AttributeList *Attr);
virtual DeclResult
ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr);
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,

Просмотреть файл

@ -273,8 +273,9 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
SourceLocation CCLoc) {
NestedNameSpecifier *Prefix
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
QualType T = QualType::getFromOpaquePtr(Ty);
return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
QualType::getFromOpaquePtr(Ty).getTypePtr());
T.getTypePtr());
}
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global

Просмотреть файл

@ -3254,12 +3254,15 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
goto CreateNewDecl;
}
// FIXME: RequireCompleteDeclContext(SS)?
if (RequireCompleteDeclContext(SS))
return DeclPtrTy::make((Decl *)0);
DC = computeDeclContext(SS);
SearchDC = DC;
// Look-up name inside 'foo::'.
PrevDecl = dyn_cast_or_null<TagDecl>(
LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
PrevDecl
= dyn_cast_or_null<TagDecl>(
LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
// A tag 'foo::bar' must already exist.
if (PrevDecl == 0) {

Просмотреть файл

@ -994,10 +994,7 @@ QualType Sema::CheckPointerToMemberOperands(
Diag(Loc, diag::err_bad_memptr_rhs)
<< OpSpelling << RType << rex->getSourceRange();
return QualType();
} else if (RequireCompleteType(Loc, QualType(MemPtr->getClass(), 0),
diag::err_memptr_rhs_incomplete,
rex->getSourceRange()))
return QualType();
}
QualType Class(MemPtr->getClass(), 0);

Просмотреть файл

@ -2155,6 +2155,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
return DeclPtrTy::make(Specialization);
}
// Explicit instantiation of a class template specialization
Sema::DeclResult
Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
unsigned TagSpec,
@ -2244,7 +2245,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
}
if (PrevDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
// C++0x [temp.explicit]p4:
// C++ DR 259, C++0x [temp.explicit]p4:
// For a given set of template parameters, if an explicit
// instantiation of a template appears after a declaration of
// an explicit specialization for that template, the explicit
@ -2342,6 +2343,84 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
return DeclPtrTy::make(Specialization);
}
// Explicit instantiation of a member class of a class template.
Sema::DeclResult
Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
const CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr) {
DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference,
KWLoc, SS, Name, NameLoc, Attr, AS_none);
if (!TagD)
return true;
TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
if (Tag->isEnum()) {
Diag(TemplateLoc, diag::err_explicit_instantiation_enum)
<< Context.getTypeDeclType(Tag);
return true;
}
CXXRecordDecl *Record = cast<CXXRecordDecl>(Tag);
CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
if (!Pattern) {
Diag(TemplateLoc, diag::err_explicit_instantiation_nontemplate_type)
<< Context.getTypeDeclType(Record);
Diag(Record->getLocation(), diag::note_nontemplate_decl_here);
return true;
}
// C++0x [temp.explicit]p2:
// [...] An explicit instantiation shall appear in an enclosing
// namespace of its template. [...]
//
// This is C++ DR 275.
if (getLangOptions().CPlusPlus0x) {
// FIXME: In C++98, we would like to turn these errors into
// warnings, dependent on a -Wc++0x flag.
DeclContext *PatternContext
= Pattern->getDeclContext()->getEnclosingNamespaceContext();
if (!CurContext->Encloses(PatternContext)) {
Diag(TemplateLoc, diag::err_explicit_instantiation_out_of_scope)
<< Record << cast<NamedDecl>(PatternContext) << SS.getRange();
Diag(Pattern->getLocation(), diag::note_previous_declaration);
}
}
// Find the enclosing template, because we need its template
// arguments to instantiate this class.
DeclContext *EnclosingTemplateCtx = Record->getDeclContext();
while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx))
EnclosingTemplateCtx = EnclosingTemplateCtx->getParent();
ClassTemplateSpecializationDecl *EnclosingTemplate
= cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx);
if (!Record->getDefinition(Context)) {
// If the class has a definition, instantiate it (and all of its
// members, recursively).
Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern,
EnclosingTemplate->getTemplateArgs(),
/*ExplicitInstantiation=*/true))
return true;
} else {
// Instantiate all of the members of class.
InstantiatingTemplate Inst(*this, TemplateLoc, Record);
InstantiateClassMembers(TemplateLoc, Record,
EnclosingTemplate->getTemplateArgs());
}
// FIXME: We don't have any representation for explicit
// instantiations of member classes. Such a representation is not
// needed for compilation, but it should be available for clients
// that want to see all of the declarations in the source code.
return TagD;
}
Sema::TypeResult
Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
const IdentifierInfo &II, SourceLocation IdLoc) {

Просмотреть файл

@ -863,7 +863,7 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
ActOnCXXNestedNameSpecifier(0, SS,
Range.getEnd(),
Range.getEnd(),
*NNS->getAsIdentifier()));
*NNS->getAsIdentifier()));
break;
}

Просмотреть файл

@ -80,7 +80,7 @@ void g() {
void (HasMembers::*pmd)() = &HasMembers::d;
}
struct Incomplete; // expected-note{{forward declaration}}
struct Incomplete;
void h() {
HasMembers hm, *phm = &hm;
@ -115,7 +115,7 @@ void h() {
Incomplete *inc;
int Incomplete::*pii = 0;
(void)inc->*pii; // expected-error {{right hand operand is a pointer to member of incomplete type 'struct Incomplete'}}
(void)(inc->*pii); // okay
}
struct OverloadsPtrMem

Просмотреть файл

@ -11,8 +11,7 @@ struct X {
// expected-error{{data member instantiated with function type 'int (int)'}} \
// expected-error{{data member instantiated with function type 'char (char)'}} \
// expected-error{{data member instantiated with function type 'short (short)'}} \
// expected-error{{data member instantiated with function type 'float (float)'}} \
// expected-error{{data member instantiated with function type 'long (long)'}}
// expected-error{{data member instantiated with function type 'float (float)'}}
};
X<int> f() { return 0; }
@ -41,7 +40,8 @@ void test_new() {
}
void test_memptr(X<long> *p1, long X<long>::*pm1,
X<long(long)> *p2, long (X<long(long)>::*pm2)(long)) {
X<long(long)> *p2,
long (X<long(long)>::*pm2)(long)) {
(void)(p1->*pm1);
(void)(p2->*pm2); // expected-note{{in instantiation of template class 'struct X<long (long)>' requested here}}
(void)((p2->*pm2)(0));
}

Просмотреть файл

@ -11,5 +11,6 @@ add_pointer<float>::type test2(int * ptr) {
return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}}
}
add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} expected-error {{unknown type name 'type'}}
add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} \
// expected-error {{unknown type name 'type'}}
test3();

Просмотреть файл

@ -71,3 +71,41 @@ void f3(X4<int&>::Inner); // okay, Inner::VeryInner, not instantiated
template struct X4<int&>; // expected-note{{instantiation}}
template struct X4<float&>; // expected-note{{instantiation}}
// Check explicit instantiation of member classes
namespace N2 {
template<typename T>
struct X5 {
struct Inner1 {
void f(T&);
};
struct Inner2 {
struct VeryInner { // expected-note 2{{instantiation}}
void g(T*); // expected-error 2{{pointer to a reference}}
};
};
};
}
template struct N2::X5<void>::Inner2;
using namespace N2;
template struct X5<int&>::Inner2; // expected-note{{instantiation}}
void f4(X5<float&>::Inner2);
template struct X5<float&>::Inner2; // expected-note{{instantiation}}
namespace N3 {
template struct N2::X5<int>::Inner2;
}
struct X6 {
struct Inner { // expected-note{{here}}
void f();
};
};
template struct X6::Inner; // expected-error{{non-templated}}