[cfe-commits] r71689 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/temp_explicit.cpp test/SemaTemplate/temp_explicit_cxx0x.cpp
Douglas Gregor
dgregor at apple.com
Wed May 13 11:28:31 PDT 2009
Author: dgregor
Date: Wed May 13 13:28:20 2009
New Revision: 71689
URL: http://llvm.org/viewvc/llvm-project?rev=71689&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaTemplate/temp_explicit_cxx0x.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/test/SemaTemplate/temp_explicit.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=71689&r1=71688&r2=71689&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed May 13 13:28:20 2009
@@ -694,11 +694,14 @@
def err_template_spec_decl_out_of_scope : Error<
"class template specialization of %0 not in namespace %1">;
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<
- "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<
- "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
def err_template_recursion_depth_exceeded : Error<
@@ -722,13 +725,15 @@
"type %0 cannot be used prior to '::' because it has no members">;
// C++ Explicit Instantiation
-def err_explicit_instantiation_redef : Error<
- "explicit instantiation of %0 occurs after "
- "%select{|explicit specialization|implicit instantiation|explicit "
- "instantiation}1">;
-def note_previous_instantiation : Note<
- "previous %select{|explicit specialization|implicit instantiation|explicit "
- "instantiation}0 is here">;
+def err_explicit_instantiation_duplicate : Error<
+ "duplicate explicit instantiation of %0">;
+def note_previous_explicit_instantiation : Note<
+ "previous explicit instantiation is here">;
+def ext_explicit_instantiation_after_specialization : Extension<
+ "explicit instantiation of %0 that occurs after an explicit "
+ "specialization will be ignored (C++0x extension)">;
+def note_previous_template_specialization : Note<
+ "previous template specialization is here">;
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=71689&r1=71688&r2=71689&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed May 13 13:28:20 2009
@@ -1882,7 +1882,8 @@
bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
ClassTemplateSpecializationDecl *PrevDecl,
SourceLocation TemplateNameLoc,
- SourceRange ScopeSpecifierRange);
+ SourceRange ScopeSpecifierRange,
+ bool ExplicitInstantiation);
virtual DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=71689&r1=71688&r2=71689&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed May 13 13:28:20 2009
@@ -1892,19 +1892,20 @@
<< TemplateRange;
}
-/// \brief Check whether a class template specialization in the
-/// current context is well-formed.
+/// \brief Check whether a class template specialization or explicit
+/// instantiation in the current context is well-formed.
///
-/// This routine determines whether a class template specialization
-/// can be declared in the current context (C++ [temp.expl.spec]p2)
-/// and emits appropriate diagnostics if there was an error. It
-/// returns true if there was an error that we cannot recover from,
-/// and false otherwise.
+/// This routine determines whether a class template specialization or
+/// explicit instantiation can be declared in the current context
+/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2) and emits
+/// appropriate diagnostics if there was an error. It returns true if
+// there was an error that we cannot recover from, and false otherwise.
bool
Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
ClassTemplateSpecializationDecl *PrevDecl,
SourceLocation TemplateNameLoc,
- SourceRange ScopeSpecifierRange) {
+ SourceRange ScopeSpecifierRange,
+ bool ExplicitInstantiation) {
// C++ [temp.expl.spec]p2:
// An explicit specialization shall be declared in the namespace
// of which the template is a member, or, for member templates, in
@@ -1920,14 +1921,15 @@
// declared.
if (CurContext->getLookupContext()->isFunctionOrMethod()) {
Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
- << ClassTemplate;
+ << ExplicitInstantiation << ClassTemplate;
return true;
}
DeclContext *DC = CurContext->getEnclosingNamespaceContext();
DeclContext *TemplateContext
= 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
// specialization must be in the same context as the template
// itself.
@@ -1949,15 +1951,26 @@
// We have a previous declaration of this entity. Make sure that
// this redeclaration (or definition) occurs in an enclosing namespace.
if (!CurContext->Encloses(TemplateContext)) {
- if (isa<TranslationUnitDecl>(TemplateContext))
- Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
- << ClassTemplate << ScopeSpecifierRange;
- else if (isa<NamespaceDecl>(TemplateContext))
- Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
- << ClassTemplate << cast<NamedDecl>(TemplateContext)
- << ScopeSpecifierRange;
+ // FIXME: In C++98, we would like to turn these errors into
+ // warnings, dependent on a -Wc++0x flag.
+ bool SuppressedDiag = false;
+ if (isa<TranslationUnitDecl>(TemplateContext)) {
+ if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
+ Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
+ << 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;
@@ -2056,7 +2069,8 @@
// the current scope.
if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
TemplateNameLoc,
- SS.getRange()))
+ SS.getRange(),
+ /*ExplicitInstantiation=*/false))
return true;
if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
@@ -2179,6 +2193,17 @@
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.
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
@@ -2206,18 +2231,55 @@
ClassTemplateSpecializationDecl *Specialization = 0;
+ bool SpecializationRequiresInstantiation = true;
if (PrevDecl) {
- if (PrevDecl->getSpecializationKind() != TSK_Undeclared) {
+ if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) {
// This particular specialization has already been declared or
// instantiated. We cannot explicitly instantiate it.
- Diag(TemplateNameLoc, diag::err_explicit_instantiation_redef)
- << Context.getTypeDeclType(PrevDecl)
- << (int)PrevDecl->getSpecializationKind();
- Diag(PrevDecl->getLocation(), diag::note_previous_instantiation)
- << (int)PrevDecl->getSpecializationKind();
+ Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate)
+ << Context.getTypeDeclType(PrevDecl);
+ Diag(PrevDecl->getLocation(),
+ diag::note_previous_explicit_instantiation);
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
// arguments was referenced but not declared, reuse that
// declaration node as our own, updating its source location to
@@ -2263,16 +2325,19 @@
CurContext->addDecl(Context, Specialization);
// C++ [temp.explicit]p3:
- //
// A definition of a class template or class member template
// shall be in scope at the point of the explicit instantiation of
// the class template or class member template.
//
// This check comes when we actually try to perform the
// instantiation.
- if (InstantiateClassTemplateSpecialization(Specialization, true))
+ if (SpecializationRequiresInstantiation &&
+ InstantiateClassTemplateSpecialization(Specialization, true))
return true;
+ // FIXME: Instantiate all of the members of the template (that
+ // haven't already been instantiated!).
+
return DeclPtrTy::make(Specialization);
}
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=71689&r1=71688&r2=71689&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed May 13 13:28:20 2009
@@ -247,10 +247,26 @@
// Build a temporary integer literal to specify the size for
// BuildArrayType. Since we have already checked the size as part of
// creating the dependent array type in the first place, we know
- // there aren't any errors.
- // FIXME: Is IntTy big enough? Maybe not, but LongLongTy causes
- // problems that I have yet to investigate.
- IntegerLiteral ArraySize(T->getSize(), SemaRef.Context.IntTy, Loc);
+ // there aren't any errors. However, we do need to determine what
+ // C++ type to give the size expression.
+ llvm::APInt Size = T->getSize();
+ 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(),
&ArraySize, T->getIndexTypeQualifier(),
Loc, Entity);
Modified: cfe/trunk/test/SemaTemplate/temp_explicit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_explicit.cpp?rev=71689&r1=71688&r2=71689&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_explicit.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_explicit.cpp Wed May 13 13:28:20 2009
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify %s
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
//
// Tests explicit instantiation of templates.
template<typename T, typename U = T> class X0 { };
@@ -24,13 +24,13 @@
// Check for explicit instantiations that come after other kinds of
// 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-error{{after}}
+template class X0<char>; // expected-warning{{ignored}}
-void foo(X0<short>) { } // expected-note{{previous}}
-template class X0<short>; // expected-error{{after}}
+void foo(X0<short>) { }
+template class X0<short>;
// Check that explicit instantiations actually produce definitions. We
// determine whether this happens by placing semantic errors in the
Added: cfe/trunk/test/SemaTemplate/temp_explicit_cxx0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_explicit_cxx0x.cpp?rev=71689&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_explicit_cxx0x.cpp (added)
+++ cfe/trunk/test/SemaTemplate/temp_explicit_cxx0x.cpp Wed May 13 13:28:20 2009
@@ -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}}
+}
More information about the cfe-commits
mailing list