Skip to content

Commit 63c29df

Browse files
authored
[Serialization] Fix assertion on re-deserialized friend template spec… (llvm#200566)
…ialization in PCH (llvm#198133) A friend function-template specialization declared inside a class template is serialized into a PCH. When the class template is later instantiated while loading the PCH, the friend specialization can be deserialized re-entrantly (VisitFriendDecl -> VisitFunctionDecl -> ... -> VisitFunctionDecl for the same specialization) at the same time as the canonical copy, producing two redeclarations of the same specialization in the template's specialization set. ASTDeclReader::VisitFunctionDecl asserted that this collision could only happen when merging declarations from different modules. Since 38b3d87, friend functions defined inside dependent class templates are loaded eagerly, so the collision can now also occur within a single PCH/AST file (non-modules build), tripping the assertion: Assertion failed: (Reader.getContext().getLangOpts().Modules && "already deserialized this template specialization"), function VisitFunctionDecl The merge that follows (mergeRedeclarable) already links the two redeclarations correctly regardless of whether modules are enabled, so the fix is to drop the modules-only assumption and let the merge run. Fixes llvm#198133
1 parent ae1d75e commit 63c29df

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -996,8 +996,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
996996
if (InsertPos)
997997
CommonPtr->Specializations.InsertNode(FTInfo, InsertPos);
998998
else {
999-
assert(Reader.getContext().getLangOpts().Modules &&
1000-
"already deserialized this template specialization");
1001999
Existing = ExistingInfo->getFunction();
10021000
}
10031001
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Regression test for https://github.com/llvm/llvm-project/issues/198133
2+
//
3+
// A friend function-template specialization declared inside a class template
4+
// is serialized into a PCH. When the class template is later instantiated
5+
// while loading the PCH, the friend specialization could be deserialized
6+
// re-entrantly (VisitFriendDecl -> VisitFunctionDecl -> ... -> VisitFunctionDecl
7+
// for the same specialization). This used to trip the assertion
8+
// "already deserialized this template specialization"
9+
// in ASTReaderDecl::VisitFunctionDecl for non-modules (PCH) builds.
10+
11+
// RUN: %clang_cc1 -std=c++17 -x c++-header -emit-pch %s -o %t.pch
12+
// RUN: %clang_cc1 -std=c++17 -include-pch %t.pch %s -fsyntax-only -verify
13+
14+
#ifndef HEADER
15+
#define HEADER
16+
17+
template <bool = false> int get_extents(const int &);
18+
template <typename> struct BoundingBoxBase {
19+
BoundingBoxBase(int) {}
20+
friend int get_extents<>(const int &);
21+
};
22+
template <class> struct BoundingBox3Base {
23+
BoundingBox3Base();
24+
};
25+
struct BoundingBoxf : BoundingBoxBase<int> {
26+
BoundingBoxf(int points) : BoundingBoxBase(points) {}
27+
};
28+
29+
#else
30+
31+
// expected-no-diagnostics
32+
void f() { BoundingBox3Base<int> build_volume; }
33+
34+
#endif

0 commit comments

Comments
 (0)