-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Description
namespace std {
template <class T> class initializer_list {};
}
template <typename T, int> class C {
public:
C(std::initializer_list<T>);
};
template <typename T> using Ptr =__remove_pointer(T) *;
template <typename T> C(T) -> C<Ptr<T>, sizeof(T)>;
class A {
public:
template <typename T1, typename T2>
T1 *some_func(T2 &&);
};
struct B : A {
int *ar = some_func<int>(C{some_func<int>(0)});
B() {}
};
I've debug in local. The crash issue caused by initializer rebuild failed in
llvm-project/clang/lib/Sema/SemaExpr.cpp
Lines 5717 to 5721 in 8e00703
| SFINAETrap Trap(*this); | |
| runWithSufficientStackSpace(Loc, [&] { | |
| Res = Immediate.TransformInitializer(Field->getInClassInitializer(), | |
| /*CXXDirectInit=*/false); | |
| }); |
SFINAETrap Trap(*this);, we can got diagnostics like the following:
./main.cpp:23:28: error: no viable constructor or deduction guide for deduction of template arguments of 'C'
23 | int *ar = some_func<int>(C{some_func<int>(0)});
| ^
./main.cpp:6:34: note: candidate template ignored: couldn't infer template argument 'T'
6 | template <typename T, int> class C {
| ^
./main.cpp:8:3: note: candidate template ignored: couldn't infer template argument ''
8 | C(std::initializer_list<T>);
| ^
./main.cpp:12:24: note: candidate template ignored: couldn't infer template argument 'T'
12 | template <typename T> C(T) -> C<Ptr<T>, sizeof(T)>;
| ^
1 error generated.
But why does the check pass during Parse phase but fails when we rebuilding CXXDefaultInitExpr? Through tracing, I found that the root cause was the parameter bool ListInitialization that passed to RebuildCXXTemporaryObjectExpr(fall throuth to Sema::BuildCXXTypeConstructExpr). During parsing, ListInitialization was true, but it became false during rebuilding, it's cause InitializationKind to become DirectInit instead of DirectListInit. Finally, causing Sema::DeduceTemplateSpecializationFromInitializer fail.
llvm-project/clang/lib/Sema/TreeTransform.h
Lines 14116 to 14121 in 8e00703
| // FIXME: We should just pass E->isListInitialization(), but we're not | |
| // prepared to handle list-initialization without a child InitListExpr. | |
| SourceLocation LParenLoc = T->getTypeLoc().getEndLoc(); | |
| return getDerived().RebuildCXXTemporaryObjectExpr( | |
| T, LParenLoc, Args, E->getEndLoc(), | |
| /*ListInitialization=*/LParenLoc.isInvalid()); |
Therefore, I think the key to the problem is to fix TreeTransform.h:14116's FIXME. As the comments in TreeTransform.h:14116 said, we should pass E->isListInitialization(), because E is actually list initialization, I have tried this modification, but it will cause 3 lit failures. We have not try to rebuild the CXXDefaultInitExpr before this PR, so it's works fine before.