Skip to content

Commit 4453feb

Browse files
committed
PR28794: Don't try to instantiate function templates which are not visible.
Reviewed by Richard Smith. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@279164 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent ec9187d commit 4453feb

File tree

8 files changed

+123
-69
lines changed

8 files changed

+123
-69
lines changed

include/clang/Sema/Sema.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5711,6 +5711,14 @@ class Sema {
57115711
TemplateTy &SuggestedTemplate,
57125712
TemplateNameKind &SuggestedKind);
57135713

5714+
bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
5715+
NamedDecl *Instantiation,
5716+
bool InstantiatedFromMember,
5717+
const NamedDecl *Pattern,
5718+
const NamedDecl *PatternDef,
5719+
TemplateSpecializationKind TSK,
5720+
bool Complain = true);
5721+
57145722
void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
57155723
TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl);
57165724

lib/Sema/SemaTemplate.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,70 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
456456
TemplateArgs);
457457
}
458458

459+
460+
/// Determine whether we would be unable to instantiate this template (because
461+
/// it either has no definition, or is in the process of being instantiated).
462+
bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
463+
NamedDecl *Instantiation,
464+
bool InstantiatedFromMember,
465+
const NamedDecl *Pattern,
466+
const NamedDecl *PatternDef,
467+
TemplateSpecializationKind TSK,
468+
bool Complain /*= true*/) {
469+
assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation));
470+
471+
if (PatternDef && (isa<FunctionDecl>(PatternDef)
472+
|| !cast<TagDecl>(PatternDef)->isBeingDefined())) {
473+
NamedDecl *SuggestedDef = nullptr;
474+
if (!hasVisibleDefinition(const_cast<NamedDecl*>(PatternDef), &SuggestedDef,
475+
/*OnlyNeedComplete*/false)) {
476+
// If we're allowed to diagnose this and recover, do so.
477+
bool Recover = Complain && !isSFINAEContext();
478+
if (Complain)
479+
diagnoseMissingImport(PointOfInstantiation, SuggestedDef,
480+
Sema::MissingImportKind::Definition, Recover);
481+
return !Recover;
482+
}
483+
return false;
484+
}
485+
486+
487+
QualType InstantiationTy;
488+
if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
489+
InstantiationTy = Context.getTypeDeclType(TD);
490+
else
491+
InstantiationTy = cast<FunctionDecl>(Instantiation)->getType();
492+
if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
493+
// Say nothing
494+
} else if (PatternDef) {
495+
Diag(PointOfInstantiation,
496+
diag::err_template_instantiate_within_definition)
497+
<< (TSK != TSK_ImplicitInstantiation)
498+
<< InstantiationTy;
499+
// Not much point in noting the template declaration here, since
500+
// we're lexically inside it.
501+
Instantiation->setInvalidDecl();
502+
} else if (InstantiatedFromMember) {
503+
Diag(PointOfInstantiation,
504+
diag::err_implicit_instantiate_member_undefined)
505+
<< InstantiationTy;
506+
Diag(Pattern->getLocation(), diag::note_member_declared_at);
507+
} else {
508+
Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
509+
<< (TSK != TSK_ImplicitInstantiation)
510+
<< InstantiationTy;
511+
Diag(Pattern->getLocation(), diag::note_template_decl_here);
512+
}
513+
514+
// In general, Instantiation isn't marked invalid to get more than one
515+
// error for multiple undefined instantiations. But the code that does
516+
// explicit declaration -> explicit definition conversion can't handle
517+
// invalid declarations, so mark as invalid in that case.
518+
if (TSK == TSK_ExplicitInstantiationDeclaration)
519+
Instantiation->setInvalidDecl();
520+
return true;
521+
}
522+
459523
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
460524
/// that the template parameter 'PrevDecl' is being shadowed by a new
461525
/// declaration at location Loc. Returns true to indicate that this is

lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,62 +1844,6 @@ namespace clang {
18441844
}
18451845
}
18461846

1847-
/// Determine whether we would be unable to instantiate this template (because
1848-
/// it either has no definition, or is in the process of being instantiated).
1849-
static bool DiagnoseUninstantiableTemplate(Sema &S,
1850-
SourceLocation PointOfInstantiation,
1851-
TagDecl *Instantiation,
1852-
bool InstantiatedFromMember,
1853-
TagDecl *Pattern,
1854-
TagDecl *PatternDef,
1855-
TemplateSpecializationKind TSK,
1856-
bool Complain = true) {
1857-
if (PatternDef && !PatternDef->isBeingDefined()) {
1858-
NamedDecl *SuggestedDef = nullptr;
1859-
if (!S.hasVisibleDefinition(PatternDef, &SuggestedDef,
1860-
/*OnlyNeedComplete*/false)) {
1861-
// If we're allowed to diagnose this and recover, do so.
1862-
bool Recover = Complain && !S.isSFINAEContext();
1863-
if (Complain)
1864-
S.diagnoseMissingImport(PointOfInstantiation, SuggestedDef,
1865-
Sema::MissingImportKind::Definition, Recover);
1866-
return !Recover;
1867-
}
1868-
return false;
1869-
}
1870-
1871-
if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
1872-
// Say nothing
1873-
} else if (PatternDef) {
1874-
assert(PatternDef->isBeingDefined());
1875-
S.Diag(PointOfInstantiation,
1876-
diag::err_template_instantiate_within_definition)
1877-
<< (TSK != TSK_ImplicitInstantiation)
1878-
<< S.Context.getTypeDeclType(Instantiation);
1879-
// Not much point in noting the template declaration here, since
1880-
// we're lexically inside it.
1881-
Instantiation->setInvalidDecl();
1882-
} else if (InstantiatedFromMember) {
1883-
S.Diag(PointOfInstantiation,
1884-
diag::err_implicit_instantiate_member_undefined)
1885-
<< S.Context.getTypeDeclType(Instantiation);
1886-
S.Diag(Pattern->getLocation(), diag::note_member_declared_at);
1887-
} else {
1888-
S.Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
1889-
<< (TSK != TSK_ImplicitInstantiation)
1890-
<< S.Context.getTypeDeclType(Instantiation);
1891-
S.Diag(Pattern->getLocation(), diag::note_template_decl_here);
1892-
}
1893-
1894-
// In general, Instantiation isn't marked invalid to get more than one
1895-
// error for multiple undefined instantiations. But the code that does
1896-
// explicit declaration -> explicit definition conversion can't handle
1897-
// invalid declarations, so mark as invalid in that case.
1898-
if (TSK == TSK_ExplicitInstantiationDeclaration)
1899-
Instantiation->setInvalidDecl();
1900-
return true;
1901-
}
1902-
19031847
/// \brief Instantiate the definition of a class from a given pattern.
19041848
///
19051849
/// \param PointOfInstantiation The point of instantiation within the
@@ -1930,7 +1874,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
19301874
bool Complain) {
19311875
CXXRecordDecl *PatternDef
19321876
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
1933-
if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
1877+
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation,
19341878
Instantiation->getInstantiatedFromMemberClass(),
19351879
Pattern, PatternDef, TSK, Complain))
19361880
return true;
@@ -2159,7 +2103,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
21592103
const MultiLevelTemplateArgumentList &TemplateArgs,
21602104
TemplateSpecializationKind TSK) {
21612105
EnumDecl *PatternDef = Pattern->getDefinition();
2162-
if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
2106+
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation,
21632107
Instantiation->getInstantiatedFromMemberEnum(),
21642108
Pattern, PatternDef, TSK,/*Complain*/true))
21652109
return true;

lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3545,7 +3545,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
35453545

35463546
// Never instantiate an explicit specialization except if it is a class scope
35473547
// explicit specialization.
3548-
if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
3548+
TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind();
3549+
if (TSK == TSK_ExplicitSpecialization &&
35493550
!Function->getClassScopeSpecializationPattern())
35503551
return;
35513552

@@ -3561,6 +3562,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
35613562
}
35623563
assert(PatternDecl && "template definition is not a template");
35633564

3565+
// FIXME: We need to track the instantiation stack in order to know which
3566+
// definitions should be visible within this instantiation.
3567+
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Function,
3568+
Function->getInstantiatedFromMemberFunction(),
3569+
PatternDecl, PatternDecl, TSK,
3570+
/*Complain*/DefinitionRequired))
3571+
return;
3572+
3573+
3574+
35643575
// Postpone late parsed template instantiations.
35653576
if (PatternDecl->isLateTemplateParsed() &&
35663577
!LateTemplateParser) {
@@ -3593,10 +3604,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
35933604
Pattern = PatternDecl->getBody(PatternDecl);
35943605
}
35953606

3596-
// FIXME: Check that the definition is visible before trying to instantiate
3597-
// it. This requires us to track the instantiation stack in order to know
3598-
// which definitions should be visible.
3599-
3607+
// FIXME: Check if we could sink these diagnostics in
3608+
// DiagnoseUninstantiableTemplate.
36003609
if (!Pattern && !PatternDecl->isDefaulted()) {
36013610
if (DefinitionRequired) {
36023611
if (Function->getPrimaryTemplate())
@@ -3612,13 +3621,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
36123621
Diag(PatternDecl->getLocation(),
36133622
diag::note_explicit_instantiation_here);
36143623
Function->setInvalidDecl();
3615-
} else if (Function->getTemplateSpecializationKind()
3616-
== TSK_ExplicitInstantiationDefinition) {
3624+
} else if (TSK == TSK_ExplicitInstantiationDefinition) {
36173625
assert(!Recursive);
36183626
PendingInstantiations.push_back(
36193627
std::make_pair(Function, PointOfInstantiation));
3620-
} else if (Function->getTemplateSpecializationKind()
3621-
== TSK_ImplicitInstantiation) {
3628+
} else if (TSK == TSK_ImplicitInstantiation) {
36223629
if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {
36233630
Diag(PointOfInstantiation, diag::warn_func_template_missing)
36243631
<< Function;
@@ -3637,8 +3644,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
36373644
// initializer or return value, and class template specializations, other
36383645
// explicit instantiation declarations have the effect of suppressing the
36393646
// implicit instantiation of the entity to which they refer.
3640-
if (Function->getTemplateSpecializationKind() ==
3641-
TSK_ExplicitInstantiationDeclaration &&
3647+
if (TSK == TSK_ExplicitInstantiationDeclaration &&
36423648
!PatternDecl->isInlined() &&
36433649
!PatternDecl->getReturnType()->getContainedAutoType())
36443650
return;
@@ -3660,6 +3666,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
36603666
PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(),
36613667
"instantiating function definition");
36623668

3669+
// The instantiation is visible here, even if it was first declared in an
3670+
// unimported module.
3671+
Function->setHidden(false);
3672+
36633673
// Copy the inner loc start from the pattern.
36643674
Function->setInnerLocStart(PatternDecl->getInnerLocStart());
36653675

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef LIB_A_HEADER
2+
#define LIB_A_HEADER
3+
4+
typedef __SIZE_TYPE__ size_t;
5+
6+
template <typename = int, size_t SlabSize = 4096, size_t = SlabSize>
7+
class BumpPtrAllocatorImpl;
8+
9+
template <typename T, size_t SlabSize, size_t SizeThreshold>
10+
void * operator new(size_t, BumpPtrAllocatorImpl<T, SlabSize, SizeThreshold> &);
11+
12+
#endif // LIB_A_HEADER
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef LIB_B_HEADER
2+
#define LIB_B_HEADER
3+
4+
#include "LibAHeader.h"
5+
6+
template <typename T, size_t SlabSize, size_t SizeThreshold>
7+
void *operator new(size_t, BumpPtrAllocatorImpl<T, SlabSize, SizeThreshold> &) {
8+
struct S {};
9+
return (void*)0xdead;
10+
}
11+
12+
#endif // LIB_B_HEADER
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module M {
2+
umbrella "Subdir" module * {export *}
3+
}

0 commit comments

Comments
 (0)