From b21ee08e57173102b67bc18237b13555066862fd Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Thu, 18 Aug 2016 22:01:25 +0000 Subject: [PATCH] PR28794: Don't try to instantiate function templates which are not visible. Reviewed by Richard Smith. llvm-svn: 279164 --- clang/include/clang/Sema/Sema.h | 8 +++ clang/lib/Sema/SemaTemplate.cpp | 64 ++++++++++++++++++++++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 60 +------------------- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 32 +++++++---- clang/test/Modules/Inputs/PR28794/LibAHeader.h | 12 ++++ clang/test/Modules/Inputs/PR28794/Subdir/Empty.h | 1 + .../Modules/Inputs/PR28794/Subdir/LibBHeader.h | 12 ++++ clang/test/Modules/Inputs/PR28794/module.modulemap | 3 + 8 files changed, 123 insertions(+), 69 deletions(-) create mode 100644 clang/test/Modules/Inputs/PR28794/LibAHeader.h create mode 100644 clang/test/Modules/Inputs/PR28794/Subdir/Empty.h create mode 100644 clang/test/Modules/Inputs/PR28794/Subdir/LibBHeader.h create mode 100644 clang/test/Modules/Inputs/PR28794/module.modulemap diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7cf84c3..d56c8c9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5711,6 +5711,14 @@ public: TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); + bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, + NamedDecl *Instantiation, + bool InstantiatedFromMember, + const NamedDecl *Pattern, + const NamedDecl *PatternDef, + TemplateSpecializationKind TSK, + bool Complain = true); + void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index a80b06f..ede1c5b 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -456,6 +456,70 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS, TemplateArgs); } + +/// Determine whether we would be unable to instantiate this template (because +/// it either has no definition, or is in the process of being instantiated). +bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, + NamedDecl *Instantiation, + bool InstantiatedFromMember, + const NamedDecl *Pattern, + const NamedDecl *PatternDef, + TemplateSpecializationKind TSK, + bool Complain /*= true*/) { + assert(isa(Instantiation) || isa(Instantiation)); + + if (PatternDef && (isa(PatternDef) + || !cast(PatternDef)->isBeingDefined())) { + NamedDecl *SuggestedDef = nullptr; + if (!hasVisibleDefinition(const_cast(PatternDef), &SuggestedDef, + /*OnlyNeedComplete*/false)) { + // If we're allowed to diagnose this and recover, do so. + bool Recover = Complain && !isSFINAEContext(); + if (Complain) + diagnoseMissingImport(PointOfInstantiation, SuggestedDef, + Sema::MissingImportKind::Definition, Recover); + return !Recover; + } + return false; + } + + + QualType InstantiationTy; + if (TagDecl *TD = dyn_cast(Instantiation)) + InstantiationTy = Context.getTypeDeclType(TD); + else + InstantiationTy = cast(Instantiation)->getType(); + if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) { + // Say nothing + } else if (PatternDef) { + Diag(PointOfInstantiation, + diag::err_template_instantiate_within_definition) + << (TSK != TSK_ImplicitInstantiation) + << InstantiationTy; + // Not much point in noting the template declaration here, since + // we're lexically inside it. + Instantiation->setInvalidDecl(); + } else if (InstantiatedFromMember) { + Diag(PointOfInstantiation, + diag::err_implicit_instantiate_member_undefined) + << InstantiationTy; + Diag(Pattern->getLocation(), diag::note_member_declared_at); + } else { + Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) + << (TSK != TSK_ImplicitInstantiation) + << InstantiationTy; + Diag(Pattern->getLocation(), diag::note_template_decl_here); + } + + // In general, Instantiation isn't marked invalid to get more than one + // error for multiple undefined instantiations. But the code that does + // explicit declaration -> explicit definition conversion can't handle + // invalid declarations, so mark as invalid in that case. + if (TSK == TSK_ExplicitInstantiationDeclaration) + Instantiation->setInvalidDecl(); + return true; +} + /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining /// that the template parameter 'PrevDecl' is being shadowed by a new /// declaration at location Loc. Returns true to indicate that this is diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 48c6a50..7e02586 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1844,62 +1844,6 @@ namespace clang { } } -/// Determine whether we would be unable to instantiate this template (because -/// it either has no definition, or is in the process of being instantiated). -static bool DiagnoseUninstantiableTemplate(Sema &S, - SourceLocation PointOfInstantiation, - TagDecl *Instantiation, - bool InstantiatedFromMember, - TagDecl *Pattern, - TagDecl *PatternDef, - TemplateSpecializationKind TSK, - bool Complain = true) { - if (PatternDef && !PatternDef->isBeingDefined()) { - NamedDecl *SuggestedDef = nullptr; - if (!S.hasVisibleDefinition(PatternDef, &SuggestedDef, - /*OnlyNeedComplete*/false)) { - // If we're allowed to diagnose this and recover, do so. - bool Recover = Complain && !S.isSFINAEContext(); - if (Complain) - S.diagnoseMissingImport(PointOfInstantiation, SuggestedDef, - Sema::MissingImportKind::Definition, Recover); - return !Recover; - } - return false; - } - - if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) { - // Say nothing - } else if (PatternDef) { - assert(PatternDef->isBeingDefined()); - S.Diag(PointOfInstantiation, - diag::err_template_instantiate_within_definition) - << (TSK != TSK_ImplicitInstantiation) - << S.Context.getTypeDeclType(Instantiation); - // Not much point in noting the template declaration here, since - // we're lexically inside it. - Instantiation->setInvalidDecl(); - } else if (InstantiatedFromMember) { - S.Diag(PointOfInstantiation, - diag::err_implicit_instantiate_member_undefined) - << S.Context.getTypeDeclType(Instantiation); - S.Diag(Pattern->getLocation(), diag::note_member_declared_at); - } else { - S.Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) - << (TSK != TSK_ImplicitInstantiation) - << S.Context.getTypeDeclType(Instantiation); - S.Diag(Pattern->getLocation(), diag::note_template_decl_here); - } - - // In general, Instantiation isn't marked invalid to get more than one - // error for multiple undefined instantiations. But the code that does - // explicit declaration -> explicit definition conversion can't handle - // invalid declarations, so mark as invalid in that case. - if (TSK == TSK_ExplicitInstantiationDeclaration) - Instantiation->setInvalidDecl(); - return true; -} - /// \brief Instantiate the definition of a class from a given pattern. /// /// \param PointOfInstantiation The point of instantiation within the @@ -1930,7 +1874,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, bool Complain) { CXXRecordDecl *PatternDef = cast_or_null(Pattern->getDefinition()); - if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation, + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, Instantiation->getInstantiatedFromMemberClass(), Pattern, PatternDef, TSK, Complain)) return true; @@ -2159,7 +2103,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK) { EnumDecl *PatternDef = Pattern->getDefinition(); - if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation, + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, Instantiation->getInstantiatedFromMemberEnum(), Pattern, PatternDef, TSK,/*Complain*/true)) return true; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1e28b35..3f4a0f6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3545,7 +3545,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Never instantiate an explicit specialization except if it is a class scope // explicit specialization. - if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind(); + if (TSK == TSK_ExplicitSpecialization && !Function->getClassScopeSpecializationPattern()) return; @@ -3561,6 +3562,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } assert(PatternDecl && "template definition is not a template"); + // FIXME: We need to track the instantiation stack in order to know which + // definitions should be visible within this instantiation. + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Function, + Function->getInstantiatedFromMemberFunction(), + PatternDecl, PatternDecl, TSK, + /*Complain*/DefinitionRequired)) + return; + + + // Postpone late parsed template instantiations. if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) { @@ -3593,10 +3604,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Pattern = PatternDecl->getBody(PatternDecl); } - // FIXME: Check that the definition is visible before trying to instantiate - // it. This requires us to track the instantiation stack in order to know - // which definitions should be visible. - + // FIXME: Check if we could sink these diagnostics in + // DiagnoseUninstantiableTemplate. if (!Pattern && !PatternDecl->isDefaulted()) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) @@ -3612,13 +3621,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Diag(PatternDecl->getLocation(), diag::note_explicit_instantiation_here); Function->setInvalidDecl(); - } else if (Function->getTemplateSpecializationKind() - == TSK_ExplicitInstantiationDefinition) { + } else if (TSK == TSK_ExplicitInstantiationDefinition) { assert(!Recursive); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); - } else if (Function->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { + } else if (TSK == TSK_ImplicitInstantiation) { if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { Diag(PointOfInstantiation, diag::warn_func_template_missing) << Function; @@ -3637,8 +3644,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // initializer or return value, and class template specializations, other // explicit instantiation declarations have the effect of suppressing the // implicit instantiation of the entity to which they refer. - if (Function->getTemplateSpecializationKind() == - TSK_ExplicitInstantiationDeclaration && + if (TSK == TSK_ExplicitInstantiationDeclaration && !PatternDecl->isInlined() && !PatternDecl->getReturnType()->getContainedAutoType()) return; @@ -3660,6 +3666,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), "instantiating function definition"); + // The instantiation is visible here, even if it was first declared in an + // unimported module. + Function->setHidden(false); + // Copy the inner loc start from the pattern. Function->setInnerLocStart(PatternDecl->getInnerLocStart()); diff --git a/clang/test/Modules/Inputs/PR28794/LibAHeader.h b/clang/test/Modules/Inputs/PR28794/LibAHeader.h new file mode 100644 index 0000000..31aa02e --- /dev/null +++ b/clang/test/Modules/Inputs/PR28794/LibAHeader.h @@ -0,0 +1,12 @@ +#ifndef LIB_A_HEADER +#define LIB_A_HEADER + +typedef __SIZE_TYPE__ size_t; + +template +class BumpPtrAllocatorImpl; + +template +void * operator new(size_t, BumpPtrAllocatorImpl &); + +#endif // LIB_A_HEADER diff --git a/clang/test/Modules/Inputs/PR28794/Subdir/Empty.h b/clang/test/Modules/Inputs/PR28794/Subdir/Empty.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/clang/test/Modules/Inputs/PR28794/Subdir/Empty.h @@ -0,0 +1 @@ + diff --git a/clang/test/Modules/Inputs/PR28794/Subdir/LibBHeader.h b/clang/test/Modules/Inputs/PR28794/Subdir/LibBHeader.h new file mode 100644 index 0000000..811c240 --- /dev/null +++ b/clang/test/Modules/Inputs/PR28794/Subdir/LibBHeader.h @@ -0,0 +1,12 @@ +#ifndef LIB_B_HEADER +#define LIB_B_HEADER + +#include "LibAHeader.h" + +template +void *operator new(size_t, BumpPtrAllocatorImpl &) { + struct S {}; + return (void*)0xdead; +} + +#endif // LIB_B_HEADER diff --git a/clang/test/Modules/Inputs/PR28794/module.modulemap b/clang/test/Modules/Inputs/PR28794/module.modulemap new file mode 100644 index 0000000..389c01a --- /dev/null +++ b/clang/test/Modules/Inputs/PR28794/module.modulemap @@ -0,0 +1,3 @@ +module M { + umbrella "Subdir" module * {export *} +} -- 2.7.4