From 4d11f84cb0f44cca08c7f7737502eafc3a916d03 Mon Sep 17 00:00:00 2001 From: Jakub Labenski Date: Mon, 19 Oct 2026 12:33:27 +0200 Subject: [PATCH] fix(templates): avoid reusing specialization without rescan info in CTAD [GH #395] compare_expressions checked, under CC_EXACT_EQUIVALENCE, that both nodes either have or lack rescan info. That check only ran when the type comparison was done, and the type comparison is skipped for variable references. As a result, a specialization such as P (b a dependent static data member) created by a member declaration, with no rescan info, could be reused for the same specialization in a constructor parameter type. Then, building the implicit deduction guide for class template argument deduction failed with the internal error "missing default rescan info". Move the rescan info check out of the type comparison block so it applies to all equivalent nodes. Add regression test regressions/ctad-dependent-member-template-arg-reuse.sft.cpp and a Changes entry. --- src/il.c | 25 ++++++++------- .../ctad-missing-rescan-info.txt | 17 ++++++++++ .../default.1.1.txt | 1 + .../default.2.1.txt | 1 + .../default.3.1.txt | 1 + .../default.4.1.txt | 1 + ...ependent-member-template-arg-reuse.sft.cpp | 31 +++++++++++++++++++ 7 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 src/pending_changes/ctad-missing-rescan-info.txt create mode 100644 tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.2.1.txt create mode 100644 tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.3.1.txt create mode 100644 tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.4.1.txt create mode 100644 tests/tests/regressions/ctad-dependent-member-template-arg-reuse.sft.cpp diff --git a/src/il.c b/src/il.c index 11db2ca050..25bab95cd2 100644 --- a/src/il.c +++ b/src/il.c @@ -8665,19 +8665,22 @@ are done. } /* if */ if (!identical_types_full(node1->type, node2->type, itf_options)) { eq = FALSE; - } else if ((options & CC_EXACT_EQUIVALENCE) && - (node1->extra.rescan_info != NULL) != - (node2->extra.rescan_info != NULL)) { - /* The two expressions are equivalent, but one has associated rescan - information and the other not. With the given option, the two - should not be considered equivalent because it could cause the - version with rescan information to be replaced by the other version, - thereby causing spurious rescan failures. (If the two nodes have - associated rescan information, that information can be assumed to - be equivalent since the expressions are equivalent.) */ - eq = FALSE; } /* if */ } /* if */ + if (eq && (options & CC_EXACT_EQUIVALENCE) && + (node1->extra.rescan_info != NULL) != + (node2->extra.rescan_info != NULL)) { + /* The two expressions are equivalent, but one has associated rescan + information and the other not. With the given option, the two + should not be considered equivalent because it could cause the + version with rescan information to be replaced by the other version, + thereby causing spurious rescan failures. (If the two nodes have + associated rescan information, that information can be assumed to + be equivalent since the expressions are equivalent.) This check is + done even when the type comparison is skipped (e.g., for variable + references). */ + eq = FALSE; + } /* if */ } /* if */ done: #if DEBUG diff --git a/src/pending_changes/ctad-missing-rescan-info.txt b/src/pending_changes/ctad-missing-rescan-info.txt new file mode 100644 index 0000000000..2bfd0538f8 --- /dev/null +++ b/src/pending_changes/ctad-missing-rescan-info.txt @@ -0,0 +1,17 @@ +[GH #395] +Internal error in CTAD rescan info for reused specializations + +An internal error ("missing default rescan info") could occur when building +an implicit deduction guide for a constructor whose parameter type is a +class template specialization with a nontype template argument referring to +a dependent static data member, if that same specialization was already used +earlier in the class (e.g., in a member declaration). For example, with +--c++17: + + template struct P {}; + template struct A { + static constexpr bool b = sizeof(T) == 1; + P m; + A(T, P); + }; + void g() { A{char{}, {}}; } // Previously caused an internal error. diff --git a/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.1.1.txt b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.1.1.txt new file mode 100644 index 0000000000..43bb995b7b --- /dev/null +++ b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.1.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=1 --c++17 Test_name.c diff --git a/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.2.1.txt b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.2.1.txt new file mode 100644 index 0000000000..08970a25b7 --- /dev/null +++ b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.2.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=2 --gnu_version 150200 Test_name.c diff --git a/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.3.1.txt b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.3.1.txt new file mode 100644 index 0000000000..24ed6ac29a --- /dev/null +++ b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.3.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=3 --clang_version 220100 Test_name.c diff --git a/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.4.1.txt b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.4.1.txt new file mode 100644 index 0000000000..f6d2c993b2 --- /dev/null +++ b/tests/tests/regressions/.ctad-dependent-member-template-arg-reuse.rto/default.4.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=4 --ms_c++17 --microsoft_version 1950 Test_name.c diff --git a/tests/tests/regressions/ctad-dependent-member-template-arg-reuse.sft.cpp b/tests/tests/regressions/ctad-dependent-member-template-arg-reuse.sft.cpp new file mode 100644 index 0000000000..646ada4719 --- /dev/null +++ b/tests/tests/regressions/ctad-dependent-member-template-arg-reuse.sft.cpp @@ -0,0 +1,31 @@ +//type:fp +//options:--c++17:--gnu_version 150200:--clang_version 220100:--ms_c++17 --microsoft_version 1950 + +// A class template specialization whose nontype template argument refers to +// a dependent static data member (P below) was first created by a member +// declaration and later reused for the same specialization in a constructor +// parameter type. The first argument expression lacked the information +// needed to redo semantic analysis, so building the implicit deduction guide +// for class template argument deduction caused an internal error ("missing +// default rescan info"). + +template constexpr bool f() { return true; } + +template struct P {}; + +template struct A { + static constexpr bool b = f(); + P m; + A(T, P); +}; + +template struct B { + static constexpr bool b = sizeof(T) == 1; + P m; + B(T, P); +}; + +void g() { + A{char{}, {}}; + B{char{}, {}}; +}