Skip to content

Commit 63e6099

Browse files
Fix cycle in importing template specialization on auto type
1 parent 50cda17 commit 63e6099

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

clang/include/clang/AST/ASTImporter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ class TypeSourceInfo;
254254
/// Declaration (from, to) pairs that are known not to be equivalent
255255
/// (which we have already complained about).
256256
NonEquivalentDeclSet NonEquivalentDecls;
257+
llvm::DenseSet<const Decl *> DeclTypeCycles;
257258

258259
using FoundDeclsTy = SmallVector<NamedDecl *, 2>;
259260
FoundDeclsTy findDeclsInToCtx(DeclContext *DC, DeclarationName Name);

clang/lib/AST/ASTImporter.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4035,7 +4035,8 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
40354035
// E.g.: auto foo() { struct X{}; return X(); }
40364036
// To avoid an infinite recursion when importing, create the FunctionDecl
40374037
// with a simplified return type.
4038-
if (hasReturnTypeDeclaredInside(D)) {
4038+
if (hasReturnTypeDeclaredInside(D) ||
4039+
Importer.DeclTypeCycles.find(D) != Importer.DeclTypeCycles.end()) {
40394040
FromReturnTy = Importer.getFromContext().VoidTy;
40404041
UsedDifferentProtoType = true;
40414042
}
@@ -4058,7 +4059,13 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
40584059
}
40594060

40604061
Error Err = Error::success();
4062+
if (!UsedDifferentProtoType) {
4063+
Importer.DeclTypeCycles.insert(D);
4064+
}
40614065
auto T = importChecked(Err, FromTy);
4066+
if (!UsedDifferentProtoType) {
4067+
Importer.DeclTypeCycles.erase(D);
4068+
}
40624069
auto TInfo = importChecked(Err, FromTSI);
40634070
auto ToInnerLocStart = importChecked(Err, D->getInnerLocStart());
40644071
auto ToEndLoc = importChecked(Err, D->getEndLoc());

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,6 +3204,56 @@ TEST_P(ImportExpr, UnresolvedMemberExpr) {
32043204
compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
32053205
}
32063206

3207+
TEST_P(ImportExpr, CycleInAutoTemplateSpec) {
3208+
MatchVerifier<Decl> Verifier;
3209+
const char *Code = R"(
3210+
template <class _CharT>
3211+
struct basic_string {
3212+
using value_type = _CharT;
3213+
};
3214+
3215+
template<typename T>
3216+
struct basic_string_view {
3217+
using value_type = T;
3218+
};
3219+
3220+
using string_view = basic_string_view<char>;
3221+
using string = basic_string<char>;
3222+
3223+
template<typename T>
3224+
struct span {
3225+
};
3226+
3227+
template <typename StringT>
3228+
auto StrCatT(span<const StringT> pieces) {
3229+
basic_string<typename StringT::value_type> result;
3230+
return result;
3231+
}
3232+
3233+
string StrCat(span<const string_view> pieces) {
3234+
return StrCatT(pieces);
3235+
}
3236+
3237+
string StrCat(span<const string> pieces) {
3238+
return StrCatT(pieces);
3239+
}
3240+
3241+
template <typename T>
3242+
auto declToImport(T pieces) {
3243+
return StrCat(pieces);
3244+
}
3245+
3246+
void test() {
3247+
span<const string> pieces;
3248+
auto result = declToImport(pieces);
3249+
}
3250+
)";
3251+
// This test reproduces the StrCatT recursion pattern with concepts and span
3252+
// that may cause infinite recursion during AST import due to circular dependencies
3253+
testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier,
3254+
functionTemplateDecl(hasName("declToImport")));
3255+
}
3256+
32073257
TEST_P(ImportExpr, ConceptNoRequirement) {
32083258
MatchVerifier<Decl> Verifier;
32093259
const char *Code = R"(

0 commit comments

Comments
 (0)