From: Douglas Gregor Date: Wed, 14 Oct 2009 20:14:33 +0000 (+0000) Subject: Testing and some minor fixes for explicit template instantiation. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=663b5a0be7261c29bc4c526a71cffcfa02d4153e;p=clang Testing and some minor fixes for explicit template instantiation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84129 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 63f909146e..106d568c9b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -174,7 +174,7 @@ class ASTContext { /// This mapping will contain an entry that maps from the VarDecl for /// X::value to the corresponding VarDecl for X::value (within the /// class template X) and will be marked TSK_ImplicitInstantiation. - llvm::DenseMap + llvm::DenseMap InstantiatedFromStaticDataMember; /// \brief Keeps track of the UnresolvedUsingDecls from which UsingDecls @@ -267,7 +267,8 @@ public: /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member /// from which it was instantiated. - MemberSpecializationInfo *getInstantiatedFromStaticDataMember(VarDecl *Var); + MemberSpecializationInfo *getInstantiatedFromStaticDataMember( + const VarDecl *Var); /// \brief Note that the static data member \p Inst is an instantiation of /// the static data member template \p Tmpl of a class template. diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 7c326dee33..972e1f6900 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -591,7 +591,7 @@ public: /// \brief If this variable is a static data member, determine what kind of /// template specialization or instantiation this is. - TemplateSpecializationKind getTemplateSpecializationKind(); + TemplateSpecializationKind getTemplateSpecializationKind() const; /// \brief If this variable is an instantiation of a static data member of a /// class template specialization, retrieves the member specialization diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b03676d877..d799bb52b9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1104,7 +1104,9 @@ def err_explicit_instantiation_ambiguous : Error< "partial ordering for explicit instantiation of %0 is ambiguous">; def note_explicit_instantiation_candidate : Note< "explicit instantiation candidate function template here %0">; - +def err_explicit_instantiation_inline : Error< + "explicit instantiation cannot be 'inline'">; + // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_type : Error< diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 85b4fd6d6c..e028186d46 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -233,9 +233,9 @@ void ASTContext::InitBuiltinTypes() { } MemberSpecializationInfo * -ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) { +ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); - llvm::DenseMap::iterator Pos + llvm::DenseMap::iterator Pos = InstantiatedFromStaticDataMember.find(Var); if (Pos == InstantiatedFromStaticDataMember.end()) return 0; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 429729ea3b..a908299bfe 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -380,7 +380,7 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() { return 0; } -TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() { +TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { if (MemberSpecializationInfo *MSI = getASTContext().getInstantiatedFromStaticDataMember(this)) return MSI->getTemplateSpecializationKind(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index acb2a67770..419c8a13c2 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1836,7 +1836,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, if (RD->isAbstract()) AbstractClassUsageDiagnoser(*this, RD); - if (!RD->isDependentType()) + if (!RD->isDependentType() && !RD->isInvalidDecl()) AddImplicitlyDeclaredMembersToClass(RD); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d56b4e114e..457b219bb0 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3647,6 +3647,19 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return true; } + // C++0x [temp.explicit]p1: + // [...] An explicit instantiation of a function template shall not use the + // inline or constexpr specifiers. + // Presumably, this also applies to member functions of class templates as + // well. + if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_explicit_instantiation_inline) + << CodeModificationHint::CreateRemoval( + SourceRange(D.getDeclSpec().getInlineSpecLoc())); + + // FIXME: check for constexpr specifier. + // Determine what kind of explicit instantiation we have. TemplateSpecializationKind TSK = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 65260c8e1e..24b83704eb 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -808,9 +808,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation), Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); - + if (Instantiation->isInvalidDecl()) + Invalid = true; + // Add any implicitly-declared members that we might need. - AddImplicitlyDeclaredMembersToClass(Instantiation); + if (!Invalid) + AddImplicitlyDeclaredMembersToClass(Instantiation); // Exit the scope of this instantiation. CurContext = PreviousContext; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 33fa28866e..28c0fa6ab9 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -246,8 +246,10 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { D->getTypeSpecStartLoc(), D->getAccess(), 0); - if (!Field) + if (!Field) { + cast(Owner)->setInvalidDecl(); return 0; + } if (Invalid) Field->setInvalidDecl(); diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp new file mode 100644 index 0000000000..becdd6b606 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s + +template +struct X { + void f(); +}; + +template inline void X::f(); // expected-error{{'inline'}} + +// FIXME: test constexpr diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp new file mode 100644 index 0000000000..896e30efb8 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp @@ -0,0 +1,89 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct C { }; + +template +struct X0 { + T value; // expected-error{{incomplete}} +}; + +// Explicitly instantiate a class template specialization +template struct X0; +template struct X0; // expected-note{{instantiation}} + +// Explicitly instantiate a function template specialization +template +void f0(T t) { + ++t; // expected-error{{cannot modify}} +} + +template void f0(int); +template void f0(long); +template void f0<>(unsigned); +template void f0(int C::*); // expected-note{{instantiation}} + +// Explicitly instantiate a member template specialization +template +struct X1 { + template + struct Inner { + T member1; + U member2; // expected-error{{incomplete}} + }; + + template + void f(T& t, U u) { + t = u; // expected-error{{incompatible}} + } +}; + +template struct X1::Inner; +template struct X1::Inner; +template struct X1::Inner; // expected-note{{instantiation}} + +template void X1::f(int&, float); +template void X1::f(int&, long); +template void X1::f<>(int&, double); +template void X1::f<>(int&, int*); // expected-note{{instantiation}} + +// Explicitly instantiate members of a class template +struct Incomplete; // expected-note{{forward declaration}} +struct NonDefaultConstructible { + NonDefaultConstructible(int); +}; + +template +struct X2 { + void f(T &t, U u) { + t = u; // expected-error{{incompatible}} + } + + struct Inner { + T member1; + U member2; // expected-error{{incomplete}} + }; + + static T static_member1; + static U static_member2; +}; + +template +T X2::static_member1 = 17; // expected-error{{incompatible type}} + +template +U X2::static_member2; // expected-error{{no matching}} + +template void X2::f(int &, float); +template void X2::f(int &, double); // expected-error{{does not refer}} +template void X2::f(int&, int*); // expected-note{{instantiation}} + +template struct X2::Inner; +template struct X2::Inner; // expected-note{{instantiation}} + +template int X2::static_member1; +template int* X2::static_member1; // expected-note{{instantiation}} +template + NonDefaultConstructible X2::static_member1; + +template + NonDefaultConstructible X2::static_member2; // expected-note{{instantiation}}