diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 4df55e6762..509f45c783 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -6123,6 +6123,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // Implicit instantiation of static data members of class templates. // FIXME: distinguish between implicit instantiations (which we need to // actually instantiate) and explicit specializations. + // FIXME: extern templates if (Var->isStaticDataMember() && Var->getInstantiatedFromStaticDataMember()) PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc)); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8bb33eb985..f8b48b218a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2977,7 +2977,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, Converted, 0); Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); - return DeclPtrTy::make(Specialization); + return DeclPtrTy::make(PrevDecl); } // If we have already (implicitly) instantiated this @@ -2985,14 +2985,19 @@ Sema::ActOnExplicitInstantiation(Scope *S, 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 - // reflect our new declaration. - Specialization = PrevDecl; - Specialization->setLocation(TemplateNameLoc); - PrevDecl = 0; - } else { + if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation || + PrevDecl->getSpecializationKind() == TSK_Undeclared) { + // 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; + } + } + + if (!Specialization) { // Create a new class template specialization declaration node for // this explicit specialization. Specialization @@ -3000,10 +3005,17 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, - Converted, 0); + Converted, PrevDecl); - ClassTemplate->getSpecializations().InsertNode(Specialization, - InsertPos); + if (PrevDecl) { + // Remove the previous declaration from the folding set, since we want + // to introduce a new declaration. + ClassTemplate->getSpecializations().RemoveNode(PrevDecl); + ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + } + + // Insert the new specialization. + ClassTemplate->getSpecializations().InsertNode(Specialization, InsertPos); } // Build the fully-sugared type for this explicit instantiation as diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 6a5235229a..adc8a94e51 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -820,11 +820,28 @@ Sema::InstantiateClassTemplateSpecialization( ClassTemplateSpec = cast( ClassTemplateSpec->getCanonicalDecl()); - // We can only instantiate something that hasn't already been - // instantiated or specialized. Fail without any diagnostics: our - // caller will provide an error message. - if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) + // Check whether we have already instantiated or specialized this class + // template specialization. + if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) { + if (ClassTemplateSpec->getSpecializationKind() == + TSK_ExplicitInstantiationDeclaration && + TSK == TSK_ExplicitInstantiationDefinition) { + // An explicit instantiation definition follows an explicit instantiation + // declaration (C++0x [temp.explicit]p10); go ahead and perform the + // explicit instantiation. + ClassTemplateSpec->setSpecializationKind(TSK); + InstantiateClassTemplateSpecializationMembers( + /*FIXME?*/ClassTemplateSpec->getPointOfInstantiation(), + ClassTemplateSpec, + TSK); + return false; + } + + // We can only instantiate something that hasn't already been + // instantiated or specialized. Fail without any diagnostics: our + // caller will provide an error message. return true; + } ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); CXXRecordDecl *Pattern = 0; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index f0597be879..dbb56611ed 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1031,6 +1031,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Instantiate the function body. OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs); + if (Body.isInvalid()) + Function->setInvalidDecl(); + ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), /*IsInstantiation=*/true); diff --git a/test/SemaTemplate/extern-templates.cpp b/test/SemaTemplate/extern-templates.cpp index 3a13d11c75..458957033e 100644 --- a/test/SemaTemplate/extern-templates.cpp +++ b/test/SemaTemplate/extern-templates.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s +// RUN: clang-cc -fsyntax-only -verify %s template class X0 { @@ -12,7 +12,7 @@ public: template void X0::f(T t) { - t = 17; + t = 17; // expected-error{{incompatible}} } extern template class X0; @@ -21,10 +21,21 @@ extern template class X0; template void X0::Inner::g(T t) { - t = 17; + t = 17; // expected-error{{incompatible}} } void test_intptr(X0 xi, X0::Inner xii) { xi.f(0); xii.g(0); } + +// FIXME: we would like the notes to point to the explicit instantiation at the +// bottom. +extern template class X0; // expected-note{{instantiation}} + +void test_longptr(X0 xl, X0::Inner xli) { + xl.f(0); + xli.g(0); // expected-note{{instantiation}} +} + +template class X0;