Improve the semantic checking for explicit instantiations of
templates. In particular: - An explicit instantiation can follow an implicit instantiation (we were improperly diagnosing this as an error, previously). - In C++0x, an explicit instantiation that follows an explicit specialization of the same template specialization is ignored. In C++98, we just emit an extension warning. - In C++0x, an explicit instantiation must be in a namespace enclosing the original template. C++98 has no such requirement. Also, fixed a longstanding FIXME regarding the integral type that is used for the size of a constant array type when it is being instantiated. llvm-svn: 71689
This commit is contained in:
parent
69921959b4
commit
f61eca93c0
|
@ -694,11 +694,14 @@ def err_template_spec_decl_out_of_scope_global : Error<
|
||||||
def err_template_spec_decl_out_of_scope : Error<
|
def err_template_spec_decl_out_of_scope : Error<
|
||||||
"class template specialization of %0 not in namespace %1">;
|
"class template specialization of %0 not in namespace %1">;
|
||||||
def err_template_spec_decl_function_scope : Error<
|
def err_template_spec_decl_function_scope : Error<
|
||||||
"class template specialization of %0 in function scope">;
|
"%select{class template specialization|explicit instantiation}0 of %1 "
|
||||||
|
"in function scope">;
|
||||||
def err_template_spec_redecl_out_of_scope : Error<
|
def err_template_spec_redecl_out_of_scope : Error<
|
||||||
"class template specialization of %0 not in a namespace enclosing %1">;
|
"%select{class template specialization|explicit instantiation}0 of %1 "
|
||||||
|
"not in a namespace enclosing %2">;
|
||||||
def err_template_spec_redecl_global_scope : Error<
|
def err_template_spec_redecl_global_scope : Error<
|
||||||
"class template specialization of %0 must occur in at global scope">;
|
"%select{class template specialization|explicit instantiation}0 of %1 must "
|
||||||
|
"occur at global scope">;
|
||||||
|
|
||||||
// C++ Template Instantiation
|
// C++ Template Instantiation
|
||||||
def err_template_recursion_depth_exceeded : Error<
|
def err_template_recursion_depth_exceeded : Error<
|
||||||
|
@ -722,13 +725,15 @@ def err_nested_name_spec_non_tag : Error<
|
||||||
"type %0 cannot be used prior to '::' because it has no members">;
|
"type %0 cannot be used prior to '::' because it has no members">;
|
||||||
|
|
||||||
// C++ Explicit Instantiation
|
// C++ Explicit Instantiation
|
||||||
def err_explicit_instantiation_redef : Error<
|
def err_explicit_instantiation_duplicate : Error<
|
||||||
"explicit instantiation of %0 occurs after "
|
"duplicate explicit instantiation of %0">;
|
||||||
"%select{|explicit specialization|implicit instantiation|explicit "
|
def note_previous_explicit_instantiation : Note<
|
||||||
"instantiation}1">;
|
"previous explicit instantiation is here">;
|
||||||
def note_previous_instantiation : Note<
|
def ext_explicit_instantiation_after_specialization : Extension<
|
||||||
"previous %select{|explicit specialization|implicit instantiation|explicit "
|
"explicit instantiation of %0 that occurs after an explicit "
|
||||||
"instantiation}0 is here">;
|
"specialization will be ignored (C++0x extension)">;
|
||||||
|
def note_previous_template_specialization : Note<
|
||||||
|
"previous template specialization is here">;
|
||||||
|
|
||||||
// C++ typename-specifiers
|
// C++ typename-specifiers
|
||||||
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
|
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
|
||||||
|
|
|
@ -1882,7 +1882,8 @@ public:
|
||||||
bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
|
bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
|
||||||
ClassTemplateSpecializationDecl *PrevDecl,
|
ClassTemplateSpecializationDecl *PrevDecl,
|
||||||
SourceLocation TemplateNameLoc,
|
SourceLocation TemplateNameLoc,
|
||||||
SourceRange ScopeSpecifierRange);
|
SourceRange ScopeSpecifierRange,
|
||||||
|
bool ExplicitInstantiation);
|
||||||
|
|
||||||
virtual DeclResult
|
virtual DeclResult
|
||||||
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||||
|
|
|
@ -1892,19 +1892,20 @@ Sema::CheckTemplateDeclScope(Scope *S,
|
||||||
<< TemplateRange;
|
<< TemplateRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Check whether a class template specialization in the
|
/// \brief Check whether a class template specialization or explicit
|
||||||
/// current context is well-formed.
|
/// instantiation in the current context is well-formed.
|
||||||
///
|
///
|
||||||
/// This routine determines whether a class template specialization
|
/// This routine determines whether a class template specialization or
|
||||||
/// can be declared in the current context (C++ [temp.expl.spec]p2)
|
/// explicit instantiation can be declared in the current context
|
||||||
/// and emits appropriate diagnostics if there was an error. It
|
/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2) and emits
|
||||||
/// returns true if there was an error that we cannot recover from,
|
/// appropriate diagnostics if there was an error. It returns true if
|
||||||
/// and false otherwise.
|
// there was an error that we cannot recover from, and false otherwise.
|
||||||
bool
|
bool
|
||||||
Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
|
Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
|
||||||
ClassTemplateSpecializationDecl *PrevDecl,
|
ClassTemplateSpecializationDecl *PrevDecl,
|
||||||
SourceLocation TemplateNameLoc,
|
SourceLocation TemplateNameLoc,
|
||||||
SourceRange ScopeSpecifierRange) {
|
SourceRange ScopeSpecifierRange,
|
||||||
|
bool ExplicitInstantiation) {
|
||||||
// C++ [temp.expl.spec]p2:
|
// C++ [temp.expl.spec]p2:
|
||||||
// An explicit specialization shall be declared in the namespace
|
// An explicit specialization shall be declared in the namespace
|
||||||
// of which the template is a member, or, for member templates, in
|
// of which the template is a member, or, for member templates, in
|
||||||
|
@ -1920,14 +1921,15 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
|
||||||
// declared.
|
// declared.
|
||||||
if (CurContext->getLookupContext()->isFunctionOrMethod()) {
|
if (CurContext->getLookupContext()->isFunctionOrMethod()) {
|
||||||
Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
|
Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
|
||||||
<< ClassTemplate;
|
<< ExplicitInstantiation << ClassTemplate;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclContext *DC = CurContext->getEnclosingNamespaceContext();
|
DeclContext *DC = CurContext->getEnclosingNamespaceContext();
|
||||||
DeclContext *TemplateContext
|
DeclContext *TemplateContext
|
||||||
= ClassTemplate->getDeclContext()->getEnclosingNamespaceContext();
|
= ClassTemplate->getDeclContext()->getEnclosingNamespaceContext();
|
||||||
if (!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) {
|
if ((!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) &&
|
||||||
|
!ExplicitInstantiation) {
|
||||||
// There is no prior declaration of this entity, so this
|
// There is no prior declaration of this entity, so this
|
||||||
// specialization must be in the same context as the template
|
// specialization must be in the same context as the template
|
||||||
// itself.
|
// itself.
|
||||||
|
@ -1949,15 +1951,26 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
|
||||||
// We have a previous declaration of this entity. Make sure that
|
// We have a previous declaration of this entity. Make sure that
|
||||||
// this redeclaration (or definition) occurs in an enclosing namespace.
|
// this redeclaration (or definition) occurs in an enclosing namespace.
|
||||||
if (!CurContext->Encloses(TemplateContext)) {
|
if (!CurContext->Encloses(TemplateContext)) {
|
||||||
if (isa<TranslationUnitDecl>(TemplateContext))
|
// FIXME: In C++98, we would like to turn these errors into
|
||||||
Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
|
// warnings, dependent on a -Wc++0x flag.
|
||||||
<< ClassTemplate << ScopeSpecifierRange;
|
bool SuppressedDiag = false;
|
||||||
else if (isa<NamespaceDecl>(TemplateContext))
|
if (isa<TranslationUnitDecl>(TemplateContext)) {
|
||||||
Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
|
if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
|
||||||
<< ClassTemplate << cast<NamedDecl>(TemplateContext)
|
Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
|
||||||
<< ScopeSpecifierRange;
|
<< ExplicitInstantiation << ClassTemplate << ScopeSpecifierRange;
|
||||||
|
else
|
||||||
|
SuppressedDiag = true;
|
||||||
|
} else if (isa<NamespaceDecl>(TemplateContext)) {
|
||||||
|
if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
|
||||||
|
Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
|
||||||
|
<< ExplicitInstantiation << ClassTemplate
|
||||||
|
<< cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
|
||||||
|
else
|
||||||
|
SuppressedDiag = true;
|
||||||
|
}
|
||||||
|
|
||||||
Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
|
if (!SuppressedDiag)
|
||||||
|
Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -2056,7 +2069,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||||
// the current scope.
|
// the current scope.
|
||||||
if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
|
if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
|
||||||
TemplateNameLoc,
|
TemplateNameLoc,
|
||||||
SS.getRange()))
|
SS.getRange(),
|
||||||
|
/*ExplicitInstantiation=*/false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
|
if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
|
||||||
|
@ -2179,6 +2193,17 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||||
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
|
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// C++0x [temp.explicit]p2:
|
||||||
|
// [...] An explicit instantiation shall appear in an enclosing
|
||||||
|
// namespace of its template. [...]
|
||||||
|
//
|
||||||
|
// This is C++ DR 275.
|
||||||
|
if (CheckClassTemplateSpecializationScope(ClassTemplate, 0,
|
||||||
|
TemplateNameLoc,
|
||||||
|
SS.getRange(),
|
||||||
|
/*ExplicitInstantiation=*/true))
|
||||||
|
return true;
|
||||||
|
|
||||||
// Translate the parser's template argument list in our AST format.
|
// Translate the parser's template argument list in our AST format.
|
||||||
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
|
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
|
||||||
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
|
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
|
||||||
|
@ -2206,18 +2231,55 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||||
|
|
||||||
ClassTemplateSpecializationDecl *Specialization = 0;
|
ClassTemplateSpecializationDecl *Specialization = 0;
|
||||||
|
|
||||||
|
bool SpecializationRequiresInstantiation = true;
|
||||||
if (PrevDecl) {
|
if (PrevDecl) {
|
||||||
if (PrevDecl->getSpecializationKind() != TSK_Undeclared) {
|
if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) {
|
||||||
// This particular specialization has already been declared or
|
// This particular specialization has already been declared or
|
||||||
// instantiated. We cannot explicitly instantiate it.
|
// instantiated. We cannot explicitly instantiate it.
|
||||||
Diag(TemplateNameLoc, diag::err_explicit_instantiation_redef)
|
Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate)
|
||||||
<< Context.getTypeDeclType(PrevDecl)
|
<< Context.getTypeDeclType(PrevDecl);
|
||||||
<< (int)PrevDecl->getSpecializationKind();
|
Diag(PrevDecl->getLocation(),
|
||||||
Diag(PrevDecl->getLocation(), diag::note_previous_instantiation)
|
diag::note_previous_explicit_instantiation);
|
||||||
<< (int)PrevDecl->getSpecializationKind();
|
|
||||||
return DeclPtrTy::make(PrevDecl);
|
return DeclPtrTy::make(PrevDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PrevDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
|
||||||
|
// 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
|
||||||
|
// instantiation has no effect.
|
||||||
|
if (!getLangOptions().CPlusPlus0x) {
|
||||||
|
Diag(TemplateNameLoc,
|
||||||
|
diag::ext_explicit_instantiation_after_specialization)
|
||||||
|
<< Context.getTypeDeclType(PrevDecl);
|
||||||
|
Diag(PrevDecl->getLocation(),
|
||||||
|
diag::note_previous_template_specialization);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new class template specialization declaration node
|
||||||
|
// for this explicit specialization. This node is only used to
|
||||||
|
// record the existence of this explicit instantiation for
|
||||||
|
// accurate reproduction of the source code; we don't actually
|
||||||
|
// use it for anything, since it is semantically irrelevant.
|
||||||
|
Specialization
|
||||||
|
= ClassTemplateSpecializationDecl::Create(Context,
|
||||||
|
ClassTemplate->getDeclContext(),
|
||||||
|
TemplateNameLoc,
|
||||||
|
ClassTemplate,
|
||||||
|
&ConvertedTemplateArgs[0],
|
||||||
|
ConvertedTemplateArgs.size(),
|
||||||
|
0);
|
||||||
|
Specialization->setLexicalDeclContext(CurContext);
|
||||||
|
CurContext->addDecl(Context, Specialization);
|
||||||
|
return DeclPtrTy::make(Specialization);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have already (implicitly) instantiated this
|
||||||
|
// specialization, there is less work to do.
|
||||||
|
if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation)
|
||||||
|
SpecializationRequiresInstantiation = false;
|
||||||
|
|
||||||
// Since the only prior class template specialization with these
|
// Since the only prior class template specialization with these
|
||||||
// arguments was referenced but not declared, reuse that
|
// arguments was referenced but not declared, reuse that
|
||||||
// declaration node as our own, updating its source location to
|
// declaration node as our own, updating its source location to
|
||||||
|
@ -2263,16 +2325,19 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
|
||||||
CurContext->addDecl(Context, Specialization);
|
CurContext->addDecl(Context, Specialization);
|
||||||
|
|
||||||
// C++ [temp.explicit]p3:
|
// C++ [temp.explicit]p3:
|
||||||
//
|
|
||||||
// A definition of a class template or class member template
|
// A definition of a class template or class member template
|
||||||
// shall be in scope at the point of the explicit instantiation of
|
// shall be in scope at the point of the explicit instantiation of
|
||||||
// the class template or class member template.
|
// the class template or class member template.
|
||||||
//
|
//
|
||||||
// This check comes when we actually try to perform the
|
// This check comes when we actually try to perform the
|
||||||
// instantiation.
|
// instantiation.
|
||||||
if (InstantiateClassTemplateSpecialization(Specialization, true))
|
if (SpecializationRequiresInstantiation &&
|
||||||
|
InstantiateClassTemplateSpecialization(Specialization, true))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// FIXME: Instantiate all of the members of the template (that
|
||||||
|
// haven't already been instantiated!).
|
||||||
|
|
||||||
return DeclPtrTy::make(Specialization);
|
return DeclPtrTy::make(Specialization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,10 +247,26 @@ InstantiateConstantArrayType(const ConstantArrayType *T,
|
||||||
// Build a temporary integer literal to specify the size for
|
// Build a temporary integer literal to specify the size for
|
||||||
// BuildArrayType. Since we have already checked the size as part of
|
// BuildArrayType. Since we have already checked the size as part of
|
||||||
// creating the dependent array type in the first place, we know
|
// creating the dependent array type in the first place, we know
|
||||||
// there aren't any errors.
|
// there aren't any errors. However, we do need to determine what
|
||||||
// FIXME: Is IntTy big enough? Maybe not, but LongLongTy causes
|
// C++ type to give the size expression.
|
||||||
// problems that I have yet to investigate.
|
llvm::APInt Size = T->getSize();
|
||||||
IntegerLiteral ArraySize(T->getSize(), SemaRef.Context.IntTy, Loc);
|
QualType Types[] = {
|
||||||
|
SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy,
|
||||||
|
SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
|
||||||
|
SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
|
||||||
|
};
|
||||||
|
const unsigned NumTypes = sizeof(Types) / sizeof(QualType);
|
||||||
|
QualType SizeType;
|
||||||
|
for (unsigned I = 0; I != NumTypes; ++I)
|
||||||
|
if (Size.getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
|
||||||
|
SizeType = Types[I];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SizeType.isNull())
|
||||||
|
SizeType = SemaRef.Context.getFixedWidthIntType(Size.getBitWidth(), false);
|
||||||
|
|
||||||
|
IntegerLiteral ArraySize(Size, SizeType, Loc);
|
||||||
return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
|
return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(),
|
||||||
&ArraySize, T->getIndexTypeQualifier(),
|
&ArraySize, T->getIndexTypeQualifier(),
|
||||||
Loc, Entity);
|
Loc, Entity);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: clang-cc -fsyntax-only -verify %s
|
// RUN: clang-cc -fsyntax-only -verify -pedantic %s
|
||||||
//
|
//
|
||||||
// Tests explicit instantiation of templates.
|
// Tests explicit instantiation of templates.
|
||||||
template<typename T, typename U = T> class X0 { };
|
template<typename T, typename U = T> class X0 { };
|
||||||
|
@ -24,13 +24,13 @@ template class X0<double> { }; // expected-error{{explicit specialization}}
|
||||||
|
|
||||||
// Check for explicit instantiations that come after other kinds of
|
// Check for explicit instantiations that come after other kinds of
|
||||||
// instantiations or declarations.
|
// instantiations or declarations.
|
||||||
template class X0<int, int>; // expected-error{{after}}
|
template class X0<int, int>; // expected-error{{duplicate}}
|
||||||
|
|
||||||
template<> class X0<char> { }; // expected-note{{previous}}
|
template<> class X0<char> { }; // expected-note{{previous}}
|
||||||
template class X0<char>; // expected-error{{after}}
|
template class X0<char>; // expected-warning{{ignored}}
|
||||||
|
|
||||||
void foo(X0<short>) { } // expected-note{{previous}}
|
void foo(X0<short>) { }
|
||||||
template class X0<short>; // expected-error{{after}}
|
template class X0<short>;
|
||||||
|
|
||||||
// Check that explicit instantiations actually produce definitions. We
|
// Check that explicit instantiations actually produce definitions. We
|
||||||
// determine whether this happens by placing semantic errors in the
|
// determine whether this happens by placing semantic errors in the
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s
|
||||||
|
namespace N1 {
|
||||||
|
|
||||||
|
template<typename T> struct X0 { }; // expected-note{{here}}
|
||||||
|
|
||||||
|
namespace Inner {
|
||||||
|
template<typename T> struct X1 { };
|
||||||
|
}
|
||||||
|
|
||||||
|
template struct X0<int>;
|
||||||
|
template struct Inner::X1<int>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> struct X2 { }; // expected-note{{here}}
|
||||||
|
|
||||||
|
template struct ::N1::Inner::X1<float>;
|
||||||
|
|
||||||
|
namespace N2 {
|
||||||
|
using namespace N1;
|
||||||
|
|
||||||
|
template struct X0<double>; // expected-error{{not in a namespace enclosing}}
|
||||||
|
|
||||||
|
template struct X2<float>; // expected-error{{at global scope}}
|
||||||
|
}
|
Loading…
Reference in New Issue