-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[Clang][ASTImporter] Fix cycle in importing template specialization on auto type with typename #162514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[Clang][ASTImporter] Fix cycle in importing template specialization on auto type with typename #162514
Conversation
@llvm/pr-subscribers-clang Author: None (ganenkokb-yandex) ChangesOn importing template specialization with auto return type cycle occurs when return type is not nested one, but typename from template arguments and other template. Full diff: https://github.com/llvm/llvm-project/pull/162514.diff 3 Files Affected:
diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h
index 4a0ca45b785a9..eea4ccccb1600 100644
--- a/clang/include/clang/AST/ASTImporter.h
+++ b/clang/include/clang/AST/ASTImporter.h
@@ -254,6 +254,7 @@ class TypeSourceInfo;
/// Declaration (from, to) pairs that are known not to be equivalent
/// (which we have already complained about).
NonEquivalentDeclSet NonEquivalentDecls;
+ llvm::DenseSet<const Decl *> DeclTypeCycles;
using FoundDeclsTy = SmallVector<NamedDecl *, 2>;
FoundDeclsTy findDeclsInToCtx(DeclContext *DC, DeclarationName Name);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f43fa8c90ad3b..0dc2e1c3b4f8b 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -4035,7 +4035,8 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// E.g.: auto foo() { struct X{}; return X(); }
// To avoid an infinite recursion when importing, create the FunctionDecl
// with a simplified return type.
- if (hasReturnTypeDeclaredInside(D)) {
+ if (hasReturnTypeDeclaredInside(D) ||
+ Importer.DeclTypeCycles.find(D) != Importer.DeclTypeCycles.end()) {
FromReturnTy = Importer.getFromContext().VoidTy;
UsedDifferentProtoType = true;
}
@@ -4058,7 +4059,13 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
Error Err = Error::success();
+ if (!UsedDifferentProtoType) {
+ Importer.DeclTypeCycles.insert(D);
+ }
auto T = importChecked(Err, FromTy);
+ if (!UsedDifferentProtoType) {
+ Importer.DeclTypeCycles.erase(D);
+ }
auto TInfo = importChecked(Err, FromTSI);
auto ToInnerLocStart = importChecked(Err, D->getInnerLocStart());
auto ToEndLoc = importChecked(Err, D->getEndLoc());
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index e7160bcf2e0c2..5f7fcdf817ea0 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -3204,6 +3204,56 @@ TEST_P(ImportExpr, UnresolvedMemberExpr) {
compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
}
+TEST_P(ImportExpr, CycleInAutoTemplateSpec) {
+ MatchVerifier<Decl> Verifier;
+ const char *Code = R"(
+ template <class _CharT>
+ struct basic_string {
+ using value_type = _CharT;
+ };
+
+ template<typename T>
+ struct basic_string_view {
+ using value_type = T;
+ };
+
+ using string_view = basic_string_view<char>;
+ using string = basic_string<char>;
+
+ template<typename T>
+ struct span {
+ };
+
+ template <typename StringT>
+ auto StrCatT(span<const StringT> pieces) {
+ basic_string<typename StringT::value_type> result;
+ return result;
+ }
+
+ string StrCat(span<const string_view> pieces) {
+ return StrCatT(pieces);
+ }
+
+ string StrCat(span<const string> pieces) {
+ return StrCatT(pieces);
+ }
+
+ template <typename T>
+ auto declToImport(T pieces) {
+ return StrCat(pieces);
+ }
+
+ void test() {
+ span<const string> pieces;
+ auto result = declToImport(pieces);
+ }
+)";
+ // This test reproduces the StrCatT recursion pattern with concepts and span
+ // that may cause infinite recursion during AST import due to circular dependencies
+ testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier,
+ functionTemplateDecl(hasName("declToImport")));
+}
+
TEST_P(ImportExpr, ConceptNoRequirement) {
MatchVerifier<Decl> Verifier;
const char *Code = R"(
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Your summary should mention ASTImporter and your subject should have |
Add comments for new member. Make RAII approach for cycles monitoring.
b76ab82
to
416fbca
Compare
Use FunctionDecl straight forward.
This approach can be used to detect any import cycle when a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly OK, I have only naming changes.
Fix naming and comment
ASTImporter on importing template specialization with auto return type faces cycle when return type is not nested one, but typename from template arguments and other template.
There is code, that prevents cycle to auto return types when nested type declared. Solved case differs somehow from nested types, but have same solution with UsedDifferentProtoType - with delayed return type determining.