-
Notifications
You must be signed in to change notification settings - Fork 12k
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
[Clang] Fix dependency computation for pack indexing expression #91933
Conversation
@llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesGiven Fixes #91885 Full diff: https://github.com/llvm/llvm-project/pull/91933.diff 2 Files Affected:
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index bad8e75b2f878..ee56c50d76512 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -376,6 +376,9 @@ ExprDependence clang::computeDependence(PackExpansionExpr *E) {
ExprDependence clang::computeDependence(PackIndexingExpr *E) {
ExprDependence D = E->getIndexExpr()->getDependence();
+ if (D & ExprDependence::Value)
+ D |= ExprDependence::TypeInstantiation;
+
ArrayRef<Expr *> Exprs = E->getExpressions();
if (Exprs.empty())
D |= (E->getPackIdExpression()->getDependence() |
diff --git a/clang/test/SemaCXX/cxx2c-pack-indexing.cpp b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
index a3e5a0931491b..764f6163710bd 100644
--- a/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
+++ b/clang/test/SemaCXX/cxx2c-pack-indexing.cpp
@@ -194,3 +194,17 @@ void h() {
// expected-note-re@-2 {{function template specialization '{{.*}}' requested here}}
}
}
+
+namespace GH91885 {
+
+void test(auto...args){
+ [&]<int idx>(){
+ using R = decltype( args...[idx] ) ;
+ }.template operator()<0>();
+}
+
+void f( ) {
+ test(1);
+}
+
+}
|
Given `foo...[idx]` if idx is value dependent, the expression is type dependent. Fixes llvm#91885 Fixes llvm#91884
066e23d
to
4cadff5
Compare
clang/lib/AST/ComputeDependence.cpp
Outdated
@@ -376,6 +376,9 @@ ExprDependence clang::computeDependence(PackExpansionExpr *E) { | |||
|
|||
ExprDependence clang::computeDependence(PackIndexingExpr *E) { | |||
ExprDependence D = E->getIndexExpr()->getDependence(); | |||
if (D & ExprDependence::Value) | |||
D |= ExprDependence::TypeInstantiation; |
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.
Does it mean "if the index expression is value-dependent, then the whole PackIndexingExpr
is type-dependent despite its expressions"? For example,
template <int N, int... E>
auto foo() {
return E...[N];
}
Should E...[N]
be treated as type-dependent regardless of the result being always an int?
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.
Probably E->getPackIdExpression()->getDependence() & ExprDependence::TypeInstantiation
?
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.
Should E...[N] be treated as type-dependent regardless of the result being always an int?
Yes. (We don't do anything to look at whether all the expressions would have the same type)
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.
NVM, you are right, we can simplify this whole thing, I'll do that shortly
clang/lib/AST/ComputeDependence.cpp
Outdated
@@ -377,7 +377,7 @@ ExprDependence clang::computeDependence(PackExpansionExpr *E) { | |||
ExprDependence clang::computeDependence(PackIndexingExpr *E) { | |||
ExprDependence D = E->getIndexExpr()->getDependence(); | |||
if (D & ExprDependence::Value) | |||
D |= ExprDependence::TypeInstantiation; | |||
D |= E->getPackIdExpression()->getDependence() & ExprDependence::Type; |
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.
The change seems reasonable to me, however with it we need to alter the way PackIndexingExpr
is handled inside the getDecltypeForExpr
, since when 1) E
is not type-dependent (int...
case) and 2) index
is instantiation-dependent we shall not directly call getSelectedExpr
.
llvm-project/clang/lib/Sema/SemaType.cpp
Lines 9739 to 9748 in ad1a65f
QualType Sema::getDecltypeForExpr(Expr *E) { | |
if (E->isTypeDependent()) | |
return Context.DependentTy; | |
Expr *IDExpr = E; | |
if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E)) | |
IDExpr = ImplCastExpr->getSubExpr(); | |
if (auto *PackExpr = dyn_cast<PackIndexingExpr>(E)) | |
IDExpr = PackExpr->getSelectedExpr(); |
llvm-project/clang/include/clang/AST/ExprCXX.h
Lines 4411 to 4415 in ad1a65f
Expr *getSelectedExpr() const { | |
std::optional<unsigned> Index = getSelectedIndex(); | |
assert(Index && "extracting the indexed expression of a dependant pack"); | |
return getTrailingObjects<Expr *>()[*Index]; | |
} |
In short, crash on the following code:
template<int...args> // notice the "int..." here.
void test(){
[&]<int idx>(){
using R = decltype( args...[idx] ) ;
}.template operator()<0>();
}
void f( ) {
test<1>();
}
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.
Possibly PackExpr->getExpressions().front()
for the type-independent PackExpr
with its IndexExpr
instantiation-dependent? I'm not sure whether we need an empty-check here.
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.
The change seems reasonable to me, however with it we need to alter the way PackIndexingExpr is handled inside the getDecltypeForExpr, since when 1) E is not type-dependent (int... case) and 2) index is instantiation-dependent we shall not directly call getSelectedExpr.
In that case (no selected expression) the pack is always type dependent. I did add a test though
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.
In that case (no selected expression) the pack is always type dependent.
I don't get it, could you explain the reason? FWIW, new test failed in CI so we may need to reconsider this.
clang/lib/Sema/SemaType.cpp
Outdated
@@ -9806,7 +9806,7 @@ QualType Sema::BuildCountAttributedArrayType(QualType WrappedTy, | |||
/// that expression, according to the rules in C++11 | |||
/// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. | |||
QualType Sema::getDecltypeForExpr(Expr *E) { | |||
if (E->isTypeDependent()) | |||
if (E->isInstantiationDependent()) |
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.
Is it... right? I was assuming this would bring such regressions e.g.
template <class T>
const int val = sizeof(T);
template <class T>
void foo() {
decltype(val<T>); // <-- this is instantiation-dependent, but not type-dependent.
}
Perhaps we can move it to line 9816 where the PackIndexingExpr
is handled?
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.
Perhaps we can move it to line 9816 where the PackIndexingExpr is handled?
I would be slightly concerned about having specific handling of PackIndexingExpr
all over the place,
or about decltype
behaving differently for pack indexing.
Then again, I'm not sure there is a scenario where it matters.
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.
So here is a thought.
If the pack indexing expression is not type dependent, decltype should just produce the type of that expression.
By that logic we do want to modify decltype so that it does something more clever than to try to use the selected expression.
I'll try to do something in that direction, but it's unclear to me under which set of circumstances we can observe that.
If a pack indexing expression has no selected expression but has a non-tytpe dependent pattern, we can use that type to compute the decltyoe type.
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.
Thanks for the prompt fix! I think this looks good now, but please wait for @erichkeane for the final stamp.
Given
foo...[idx]
if idx is value dependent, the expression is type dependent.Fixes #91885
Fixes #91884