Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit de0c61b

Browse files
committed
PR31469: Don't add friend template class decls to redecl chain in dependent contexts.
Fixes a crash in modules where the template class decl becomes the most recent decl in the redeclaration chain and forcing the template instantiator try to instantiate the friend declaration, rather than the template definition. In practice, A::list<int> produces a TemplateSpecializationType A::__1::list<int, allocator<type-parameter-0-0> >' failing to replace to subsitute the default argument to allocator<int>. Kudos Richard Smith (D28399). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291753 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 5ceef6b commit de0c61b

11 files changed

+61
-12
lines changed

include/clang/AST/DeclTemplate.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -2028,8 +2028,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
20282028
SourceLocation L,
20292029
DeclarationName Name,
20302030
TemplateParameterList *Params,
2031-
NamedDecl *Decl,
2032-
ClassTemplateDecl *PrevDecl);
2031+
NamedDecl *Decl);
20332032

20342033
/// \brief Create an empty class template node.
20352034
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);

lib/AST/ASTImporter.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -4671,8 +4671,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
46714671

46724672
ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC,
46734673
Loc, Name, TemplateParams,
4674-
D2Templated,
4675-
/*PrevDecl=*/nullptr);
4674+
D2Templated);
46764675
D2Templated->setDescribedClassTemplate(D2);
46774676

46784677
D2->setAccess(D->getAccess());

lib/AST/DeclTemplate.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -297,12 +297,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
297297
SourceLocation L,
298298
DeclarationName Name,
299299
TemplateParameterList *Params,
300-
NamedDecl *Decl,
301-
ClassTemplateDecl *PrevDecl) {
300+
NamedDecl *Decl) {
302301
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
303302
ClassTemplateDecl *New = new (C, DC) ClassTemplateDecl(C, DC, L, Name,
304303
Params, Decl);
305-
New->setPreviousDecl(PrevDecl);
306304
return New;
307305
}
308306

lib/Sema/SemaTemplate.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -1224,9 +1224,17 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
12241224
}
12251225
}
12261226

1227+
// If this is a templated friend in a dependent context we should not put it
1228+
// on the redecl chain. In some cases, the templated friend can be the most
1229+
// recent declaration tricking the template instantiator to make substitutions
1230+
// there.
1231+
// FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious
1232+
bool ShouldAddRedecl
1233+
= !(TUK == TUK_Friend && CurContext->isDependentContext());
1234+
12271235
CXXRecordDecl *NewClass =
12281236
CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
1229-
PrevClassTemplate?
1237+
PrevClassTemplate && ShouldAddRedecl ?
12301238
PrevClassTemplate->getTemplatedDecl() : nullptr,
12311239
/*DelayTypeCreation=*/true);
12321240
SetNestedNameSpecifier(NewClass, SS);
@@ -1245,7 +1253,11 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
12451253
ClassTemplateDecl *NewTemplate
12461254
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
12471255
DeclarationName(Name), TemplateParams,
1248-
NewClass, PrevClassTemplate);
1256+
NewClass);
1257+
1258+
if (ShouldAddRedecl)
1259+
NewTemplate->setPreviousDecl(PrevClassTemplate);
1260+
12491261
NewClass->setDescribedClassTemplate(NewTemplate);
12501262

12511263
if (ModulePrivateLoc.isValid())

lib/Sema/SemaTemplateInstantiateDecl.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -1219,8 +1219,10 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
12191219

12201220
ClassTemplateDecl *Inst
12211221
= ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(),
1222-
D->getIdentifier(), InstParams, RecordInst,
1223-
PrevClassTemplate);
1222+
D->getIdentifier(), InstParams, RecordInst);
1223+
assert(!(isFriend && Owner->isDependentContext()));
1224+
Inst->setPreviousDecl(PrevClassTemplate);
1225+
12241226
RecordInst->setDescribedClassTemplate(Inst);
12251227

12261228
if (isFriend) {

test/Misc/ast-dump-decl.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,6 @@ namespace testCanonicalTemplate {
336336
// CHECK-NEXT: ClassTemplateDecl{{.*}} TestClassTemplate
337337
// CHECK-NEXT: TemplateTypeParmDecl
338338
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
339-
// CHECK-NEXT: ClassTemplateSpecialization{{.*}} 'TestClassTemplate'
340339
// CHECK-NEXT: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
341340
// CHECK-NEXT: TemplateArgument{{.*}}A
342341
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate

test/Modules/Inputs/PR31469/empty.h

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// This file is triggers loading of module M.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module M {
2+
module "textual_shadow" { header "textual_file_shadow.h" export *}
3+
module "trigger" { header "empty.h" export * }
4+
export *
5+
}

test/Modules/Inputs/PR31469/textual.h

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace A {
2+
inline
3+
namespace __1 {
4+
template <class _Tp> class allocator;
5+
template <class _Tp, class _Alloc = allocator<_Tp>> class list;
6+
template <class _VoidPtr> class __list_iterator {
7+
//template <class> friend class list; // causes another crash in ASTDeclReader::attachPreviousDecl
8+
template <class, class> friend class list;
9+
};
10+
template <class _Tp, class _Alloc> class __list_imp {};
11+
template <class _Tp, class _Alloc> class list : __list_imp<_Tp, _Alloc> {
12+
public:
13+
list() {}
14+
};
15+
template <class _Tp> void f(list<_Tp>);
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "textual.h"
2+

test/Modules/pr31469.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: rm -rf %t
2+
// RUN: %clang_cc1 -std=c++11 -I%S/Inputs/PR31469 -verify %s
3+
// RUN: %clang_cc1 -std=c++11 -I%S/Inputs/PR31469 -fmodules -fmodules-local-submodule-visibility \
4+
// RUN: -fimplicit-module-maps -fmodules-cache-path=%t -verify %s
5+
6+
#include "textual.h"
7+
#include "empty.h"
8+
9+
namespace A {
10+
template <class _Tp> void f();
11+
}
12+
13+
A::list<int> use;
14+
15+
// expected-no-diagnostics

0 commit comments

Comments
 (0)