diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 13 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 16 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 135 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 3 | ||||
-rw-r--r-- | test/SemaTemplate/temp_explicit.cpp | 31 | ||||
-rw-r--r-- | www/cxx_status.html | 2 |
7 files changed, 200 insertions, 10 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ed56cad330..466f5495eb 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -704,8 +704,8 @@ def err_template_recursion_depth_exceeded : Error< def note_template_recursion_depth : Note< "use -ftemplate-depth-N to increase recursive template instantiation depth">; -def err_template_implicit_instantiate_undefined : Error< - "implicit instantiation of undefined template %0">; +def err_template_instantiate_undefined : Error< + "%select{implicit|explicit}0 instantiation of undefined template %1">; def err_implicit_instantiate_member_undefined : Error< "implicit instantiation of undefined member %0">; def note_template_class_instantiation_here : Note< @@ -719,6 +719,15 @@ def err_field_instantiates_to_function : Error< def err_nested_name_spec_non_tag : Error< "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">; + // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_found_global : Error< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 8356509550..2e617f573b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1895,6 +1895,19 @@ public: AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists); + virtual DeclResult + ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr); + bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -2092,7 +2105,8 @@ public: bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs); + const TemplateArgumentList &TemplateArgs, + bool ExplicitInstantiation); bool InstantiateClassTemplateSpecialization( diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index fc44217252..c80bb882f6 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2141,6 +2141,141 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, return DeclPtrTy::make(Specialization); } +Sema::DeclResult +Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy TemplateD, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr) { + // Find the class template we're specializing + TemplateName Name = TemplateD.getAsVal<TemplateName>(); + ClassTemplateDecl *ClassTemplate + = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); + + // Check that the specialization uses the same tag kind as the + // original template. + TagDecl::TagKind Kind; + switch (TagSpec) { + default: assert(0 && "Unknown tag type!"); + case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; + case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; + case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; + } + if (!isAcceptableTagRedeclaration( + ClassTemplate->getTemplatedDecl()->getTagKind(), + Kind)) { + Diag(KWLoc, diag::err_use_with_wrong_tag) + << ClassTemplate + << CodeModificationHint::CreateReplacement(KWLoc, + ClassTemplate->getTemplatedDecl()->getKindName()); + Diag(ClassTemplate->getTemplatedDecl()->getLocation(), + diag::note_previous_use); + Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); + } + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + // Check that the template argument list is well-formed for this + // template. + llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, + &TemplateArgs[0], TemplateArgs.size(), + RAngleLoc, ConvertedTemplateArgs)) + return true; + + assert((ConvertedTemplateArgs.size() == + ClassTemplate->getTemplateParameters()->size()) && + "Converted template argument list is too short!"); + + // Find the class template specialization declaration that + // corresponds to these arguments. + llvm::FoldingSetNodeID ID; + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *PrevDecl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + + ClassTemplateSpecializationDecl *Specialization = 0; + + if (PrevDecl) { + if (PrevDecl->getSpecializationKind() != TSK_Undeclared) { + // 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(); + return DeclPtrTy::make(PrevDecl); + } + + // 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 + // reflect our new declaration. + Specialization = PrevDecl; + Specialization->setLocation(TemplateNameLoc); + PrevDecl = 0; + } else { + // Create a new class template specialization declaration node for + // this explicit specialization. + Specialization + = ClassTemplateSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateNameLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + 0); + + ClassTemplate->getSpecializations().InsertNode(Specialization, + InsertPos); + } + + // Build the fully-sugared type for this explicit instantiation as + // the user wrote in the explicit instantiation itself. This means + // that we'll pretty-print the type retrieved from the + // specialization's declaration the way that the user actually wrote + // the explicit instantiation, rather than formatting the name based + // on the "canonical" representation used to store the template + // arguments in the specialization. + QualType WrittenTy + = Context.getTemplateSpecializationType(Name, + &TemplateArgs[0], + TemplateArgs.size(), + Context.getTypeDeclType(Specialization)); + Specialization->setTypeAsWritten(WrittenTy); + TemplateArgsIn.release(); + + // Add the explicit instantiation into its lexical context. However, + // since explicit instantiations are never found by name lookup, we + // just put it into the declaration context directly. + Specialization->setLexicalDeclContext(CurContext); + 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)) + return true; + + return DeclPtrTy::make(Specialization); +} + Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 0fe6cee882..ce8cbe0f43 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -666,7 +666,8 @@ Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs) { + const TemplateArgumentList &TemplateArgs, + bool ExplicitInstantiation) { bool Invalid = false; CXXRecordDecl *PatternDef @@ -678,8 +679,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_member_of_template_here); } else { - Diag(PointOfInstantiation, - diag::err_template_implicit_instantiate_undefined) + Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) + << ExplicitInstantiation << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_template_decl_here); } @@ -766,7 +767,8 @@ Sema::InstantiateClassTemplateSpecialization( return InstantiateClass(ClassTemplateSpec->getLocation(), ClassTemplateSpec, Pattern, - ClassTemplateSpec->getTemplateArgs()); + ClassTemplateSpec->getTemplateArgs(), + ExplicitInstantiation); } /// \brief Instantiate a nested-name-specifier. diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f3a31ea0de..d04a5ad6c5 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1115,7 +1115,8 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, Parent && !Spec; Parent = Parent->getParent()) Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent); assert(Spec && "Not a member of a class template specialization?"); - return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs()); + return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), + /*ExplicitInstantiation=*/false); } } } diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp index 884fc38167..527532cfa9 100644 --- a/test/SemaTemplate/temp_explicit.cpp +++ b/test/SemaTemplate/temp_explicit.cpp @@ -7,8 +7,9 @@ namespace N { template<typename T, typename U = T> class X1 { }; } +// Check the syntax of explicit instantiations. template class X0<int, float>; -template class X0<int>; +template class X0<int>; // expected-note{{previous}} template class N::X1<int>; template class ::N::X1<int, float>; @@ -16,4 +17,32 @@ template class ::N::X1<int, float>; using namespace N; template class X1<float>; +// Check for some bogus syntax that probably means that the user +// wanted to write an explicit specialization, but forgot the '<>' +// after 'template'. template class X0<double> { }; // expected-error{{explicit specialization}} + +// Check for explicit instantiations that come after other kinds of +// instantiations or declarations. +template class X0<int, int>; // expected-error{{after}} + +template<> class X0<char> { }; // expected-note{{previous}} +template class X0<char>; // expected-error{{after}} + +void foo(X0<short>) { } // expected-note{{previous}} +template class X0<short>; // expected-error{{after}} + +// Check that explicit instantiations actually produce definitions. We +// determine whether this happens by placing semantic errors in the +// definition of the template we're instantiating. +template<typename T> struct X2; // expected-note{{declared here}} + +template struct X2<float>; // expected-error{{undefined template}} + +template<typename T> +struct X2 { + void f0(T*); // expected-error{{pointer to a reference}} +}; + +template struct X2<int>; // okay +template struct X2<int&>; // expected-note{{in instantiation of}} diff --git a/www/cxx_status.html b/www/cxx_status.html index 9be7ffc274..d85d451f55 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -2055,7 +2055,7 @@ welcome!</p> <td> 14.7.2 [temp.explicit]</td> <td class="basic" align="center"></td> <td class="basic" align="center"></td> - <td class="broken" align="center"></td> + <td class="basic" align="center"></td> <td class="broken" align="center"></td> <td>Function templates cannot be instantiated</td> </tr> |