зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
88f1ba0f04
Коммит
3f5b61c394
|
@ -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}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче