-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Sema] Fix computations of "unexpanded packs" in substituted lambdas #99882
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -353,7 +353,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, | |
} | ||
|
||
if (!EnclosingStmtExpr) { | ||
LSI->ContainsUnexpandedParameterPack = true; | ||
// It is ok to have unexpanded packs in captures, template parameters | ||
// and parameters too, but only the body statement does not store this | ||
// flag, so we have to propagate it through LamdaScopeInfo. | ||
if (LSI->AfterParameterList) | ||
LSI->BodyContainsUnexpandedParameterPack = true; | ||
Comment on lines
+356
to
+360
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, one thing I didn't notice in #86265 is that we could propagate up the unexpanded pack flag for statements through calls to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this just force us to do more work - going over the lambda twice is not ideal There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait I thought it is my approach that goes through the lambda body twice in a transformation. I didn't see additional calls to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, there aren't any additional recursive traversals. It's only a shallow traversal over the fields of the lambda itself and a few of their members. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's shallow but it's also work that we could avoid doing entirely - at least during parsing just by not having this if. |
||
return false; | ||
} | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be very nice if you can merge other tests from #86265 e.g. tests including constraints/noexcepts specifiers. That way this could completely supersede that. |
||
// expected-no-diagnostics | ||
struct tuple { | ||
int x[3]; | ||
}; | ||
|
||
template <class F> | ||
int apply(F f, tuple v) { | ||
return f(v.x[0], v.x[1], v.x[2]); | ||
} | ||
|
||
int Cartesian1(auto x, auto y) { | ||
return apply([&](auto... xs) { | ||
return (apply([xs](auto... ys) { | ||
return (ys + ...); | ||
}, y) + ...); | ||
}, x); | ||
} | ||
|
||
int Cartesian2(auto x, auto y) { | ||
return apply([&](auto... xs) { | ||
return (apply([zs = xs](auto... ys) { | ||
return (ys + ...); | ||
}, y) + ...); | ||
}, x); | ||
} | ||
|
||
template <int ...> struct Ints{}; | ||
template <int> struct Choose { | ||
template<class> struct Templ; | ||
}; | ||
template <int ...x> | ||
int Cartesian3(auto y) { | ||
return [&]<int ...xs>(Ints<xs...>) { | ||
// check in default template arguments for | ||
// - type template parameters, | ||
(void)(apply([]<class = decltype(xs)>(auto... ys) { | ||
return (ys + ...); | ||
}, y) + ...); | ||
// - template template parameters. | ||
(void)(apply([]<template<class> class = Choose<xs>::template Templ>(auto... ys) { | ||
return (ys + ...); | ||
}, y) + ...); | ||
// - non-type template parameters, | ||
return (apply([]<int = xs>(auto... ys) { | ||
return (ys + ...); | ||
}, y) + ...); | ||
|
||
}(Ints<x...>()); | ||
} | ||
|
||
template <int ...x> | ||
int Cartesian4(auto y) { | ||
return [&]<int ...xs>(Ints<xs...>) { | ||
return (apply([]<decltype(xs) xx = 1>(auto... ys) { | ||
return (ys + ...); | ||
}, y) + ...); | ||
}(Ints<x...>()); | ||
} | ||
|
||
int Cartesian5(auto x, auto y) { | ||
return apply([&](auto... xs) { | ||
return (apply([](auto... ys) __attribute__((diagnose_if(!__is_same(decltype(xs), int), "message", "error"))) { | ||
return (ys + ...); | ||
}, y) + ...); | ||
}, x); | ||
} | ||
|
||
|
||
int main() { | ||
auto x = tuple({1, 2, 3}); | ||
auto y = tuple({4, 5, 6}); | ||
Cartesian1(x, y); | ||
Cartesian2(x, y); | ||
Cartesian3<1,2,3>(y); | ||
Cartesian4<1,2,3>(y); | ||
Cartesian5(x, y); | ||
} |
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.
This change is completely unrelated, feel free to make an NFC patch for that