From: Douglas Gregor Date: Tue, 27 Oct 2009 18:42:08 +0000 (+0000) Subject: An explicit instantiation definition only instantiations those class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0d03514da06dffb39a260a1228ea3fd01d196fa4;p=clang An explicit instantiation definition only instantiations those class members that have a definition. Also, use CheckSpecializationInstantiationRedecl as part of this instantiation to make sure that we diagnose the various kinds of problems that can occur with explicit instantiations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85270 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 214febecf2..8071aba7c5 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -605,6 +605,9 @@ public: /// \brief Determine whether this is or was instantiated from an out-of-line /// definition of a static data member. bool isOutOfLine() const; + + /// \brief If this is a static data member, find its out-of-line definition. + VarDecl *getOutOfLineDefinition(); /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 903d9438ac..38eb3371fe 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -383,6 +383,19 @@ bool VarDecl::isOutOfLine() const { return false; } +VarDecl *VarDecl::getOutOfLineDefinition() { + if (!isStaticDataMember()) + return 0; + + for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end(); + RD != RDEnd; ++RD) { + if (RD->getLexicalDeclContext()->isFileContext()) + return *RD; + } + + return 0; +} + VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast(MSI->getInstantiatedFrom()); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a40cdf390c..32f4ce0732 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2577,6 +2577,14 @@ public: MultiTemplateParamsArg TemplateParameterLists, Declarator &D); + bool + CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 4419ad04a2..638e00cb1d 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3073,8 +3073,6 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, /// for those cases where they are required and determining whether the /// new specialization/instantiation will have any effect. /// -/// \param S the semantic analysis object. -/// /// \param NewLoc the location of the new explicit specialization or /// instantiation. /// @@ -3092,14 +3090,13 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, /// /// \returns true if there was an error that should prevent the introduction of /// the new declaration into the AST, false otherwise. -static bool -CheckSpecializationInstantiationRedecl(Sema &S, - SourceLocation NewLoc, - TemplateSpecializationKind NewTSK, - NamedDecl *PrevDecl, - TemplateSpecializationKind PrevTSK, - SourceLocation PrevPointOfInstantiation, - bool &SuppressNew) { +bool +Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew) { SuppressNew = false; switch (NewTSK) { @@ -3137,9 +3134,9 @@ CheckSpecializationInstantiationRedecl(Sema &S, // before the first use of that specialization that would cause an // implicit instantiation to take place, in every translation unit in // which such a use occurs; no diagnostic is required. - S.Diag(NewLoc, diag::err_specialization_after_instantiation) + Diag(NewLoc, diag::err_specialization_after_instantiation) << PrevDecl; - S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) + Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) << (PrevTSK != TSK_ImplicitInstantiation); return true; @@ -3172,10 +3169,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // If an entity is the subject of both an explicit instantiation // declaration and an explicit instantiation definition in the same // translation unit, the definition shall follow the declaration. - S.Diag(NewLoc, - diag::err_explicit_instantiation_declaration_after_definition); - S.Diag(PrevPointOfInstantiation, - diag::note_explicit_instantiation_definition_here); + Diag(NewLoc, + diag::err_explicit_instantiation_declaration_after_definition); + Diag(PrevPointOfInstantiation, + diag::note_explicit_instantiation_definition_here); assert(PrevPointOfInstantiation.isValid() && "Explicit instantiation without point of instantiation?"); SuppressNew = true; @@ -3201,10 +3198,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // In C++98/03 mode, we only give an extension warning here, because it // is not not harmful to try to explicitly instantiate something that // has been explicitly specialized. - if (!S.getLangOptions().CPlusPlus0x) { - S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) + if (!getLangOptions().CPlusPlus0x) { + Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) << PrevDecl; - S.Diag(PrevDecl->getLocation(), + Diag(PrevDecl->getLocation(), diag::note_previous_template_specialization); } SuppressNew = true; @@ -3220,10 +3217,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // For a given template and a given set of template-arguments, // - an explicit instantiation definition shall appear at most once // in a program, - S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate) + Diag(NewLoc, diag::err_explicit_instantiation_duplicate) << PrevDecl; - S.Diag(PrevPointOfInstantiation, - diag::note_previous_explicit_instantiation); + Diag(PrevPointOfInstantiation, + diag::note_previous_explicit_instantiation); SuppressNew = true; return false; } @@ -3336,7 +3333,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is - // explicitly specialized then that spe- cialization shall be declared + // explicitly specialized then that specialization shall be declared // before the first use of that specialization that would cause an implicit // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. @@ -3662,7 +3659,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (PrevDecl) { bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK, PrevDecl, PrevDecl->getSpecializationKind(), PrevDecl->getPointOfInstantiation(), @@ -3738,7 +3735,11 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->getDefinition(Context)); if (!Def) InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); - else // Instantiate the members of this class template specialization. + + // Instantiate the members of this class template specialization. + Def = cast_or_null( + Specialization->getDefinition(Context)); + if (Def) InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); return DeclPtrTy::make(Specialization); @@ -3820,7 +3821,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); bool SuppressNew = false; assert(MSInfo && "No member specialization information?"); - if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, PrevDecl, MSInfo->getTemplateSpecializationKind(), MSInfo->getPointOfInstantiation(), @@ -3844,13 +3845,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, Diag(Pattern->getLocation(), diag::note_forward_declaration) << Pattern; return true; - } else if (InstantiateClass(NameLoc, Record, Def, - getTemplateInstantiationArgs(Record), - TSK)) - return true; - } else // Instantiate all of the members of the class. - InstantiateClassMembers(NameLoc, RecordDef, - getTemplateInstantiationArgs(Record), TSK); + } else { + if (InstantiateClass(NameLoc, Record, Def, + getTemplateInstantiationArgs(Record), + TSK)) + return true; + + RecordDef = cast_or_null(Record->getDefinition(Context)); + if (!RecordDef) + return true; + } + } + + // Instantiate all of the members of the class. + InstantiateClassMembers(NameLoc, RecordDef, + getTemplateInstantiationArgs(Record), TSK); // FIXME: We don't have any representation for explicit instantiations of // member classes. Such a representation is not needed for compilation, but it @@ -3969,8 +3978,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); assert(MSInfo && "Missing static data member specialization info?"); bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, - Prev, + if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev, MSInfo->getTemplateSpecializationKind(), MSInfo->getPointOfInstantiation(), SuppressNew)) @@ -4069,7 +4077,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (PrevDecl) { bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, PrevDecl, PrevDecl->getTemplateSpecializationKind(), PrevDecl->getPointOfInstantiation(), diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 22d1e165f0..14930134da 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -914,13 +914,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); - // If this is an explicit instantiation, instantiate our members, too. - if (!Invalid && TSK != TSK_ImplicitInstantiation) { - Inst.Clear(); - InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs, - TSK); - } - return Invalid; } @@ -944,9 +937,6 @@ Sema::InstantiateClassTemplateSpecialization( // declaration (C++0x [temp.explicit]p10); go ahead and perform the // explicit instantiation. ClassTemplateSpec->setSpecializationKind(TSK); - InstantiateClassTemplateSpecializationMembers(PointOfInstantiation, - ClassTemplateSpec, - TSK); return false; } @@ -1089,48 +1079,112 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, for (DeclContext::decl_iterator D = Instantiation->decls_begin(), DEnd = Instantiation->decls_end(); D != DEnd; ++D) { + bool SuppressNew = false; if (FunctionDecl *Function = dyn_cast(*D)) { - if (Function->getInstantiatedFromMemberFunction()) { - // If this member was explicitly specialized, do nothing. - if (Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization) + if (FunctionDecl *Pattern + = Function->getInstantiatedFromMemberFunction()) { + MemberSpecializationInfo *MSInfo + = Function->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Function, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) continue; - Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + if (Function->getBody()) + continue; + + if (TSK == TSK_ExplicitInstantiationDefinition) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (!Pattern->getBody()) + continue; + + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + + InstantiateFunctionDefinition(PointOfInstantiation, Function); + } else { + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } } - - if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition) - InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast(*D)) { if (Var->isStaticDataMember()) { - // If this member was explicitly specialized, do nothing. - if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Var, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) continue; - Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); - - if (TSK == TSK_ExplicitInstantiationDefinition) + if (TSK == TSK_ExplicitInstantiationDefinition) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (!Var->getInstantiatedFromStaticDataMember() + ->getOutOfLineDefinition()) + continue; + + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); - } + } else { + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } + } } else if (CXXRecordDecl *Record = dyn_cast(*D)) { if (Record->isInjectedClassName()) continue; - assert(Record->getInstantiatedFromMemberClass() && - "Missing instantiated-from-template information"); - - // If this member was explicitly specialized, do nothing. - if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Record, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) continue; - if (!Record->getDefinition(Context)) - InstantiateClass(PointOfInstantiation, Record, - Record->getInstantiatedFromMemberClass(), + CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); + assert(Pattern && "Missing instantiated-from-template information"); + + if (!Record->getDefinition(Context)) { + if (!Pattern->getDefinition(Context)) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (TSK == TSK_ExplicitInstantiationDeclaration) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } + + continue; + } + + InstantiateClass(PointOfInstantiation, Record, Pattern, TemplateArgs, TSK); + } - InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs, - TSK); + Pattern = cast_or_null(Record->getDefinition(Context)); + if (Pattern) + InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs, + TSK); } } } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 422a7bc04d..c9319c58ae 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1231,24 +1231,17 @@ void Sema::InstantiateStaticDataMemberDefinition( // Find the out-of-line definition of this static data member. VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); - bool FoundOutOfLineDef = false; assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); - for (VarDecl::redecl_iterator RD = Def->redecls_begin(), - RDEnd = Def->redecls_end(); - RD != RDEnd; ++RD) { - if (RD->getLexicalDeclContext()->isFileContext()) { - Def = *RD; - FoundOutOfLineDef = true; - } - } + assert(Def->isStaticDataMember() && "Not a static data member?"); + Def = Def->getOutOfLineDefinition(); - if (!FoundOutOfLineDef) { + if (!Def) { // We did not find an out-of-line definition of this static data member, // so we won't perform any instantiation. Rather, we rely on the user to // instantiate this definition (or provide a specialization for it) in // another translation unit. if (DefinitionRequired) { + Def = Var->getInstantiatedFromStaticDataMember(); Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 2 << Var->getDeclName() << Var->getDeclContext(); diff --git a/test/CXX/temp/temp.spec/temp.explicit/p8.cpp b/test/CXX/temp/temp.spec/temp.explicit/p8.cpp new file mode 100644 index 0000000000..9a5bd3245c --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p8.cpp @@ -0,0 +1,27 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template +struct X0 { + struct MemberClass; + + T* f0(T* ptr); + + static T* static_member; +}; + +template class X0; // okay +template class X0; // okay; nothing gets instantiated. + +template +struct X0::MemberClass { + T member; +}; + +template +T* X0::f0(T* ptr) { + return ptr + 1; +} + +template +T* X0::static_member = 0; +