Skip to content

[clang][Sema] Avoid non-empty unexpanded pack assertion for FunctionParmPackExpr #69224

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

Merged
merged 1 commit into from
Nov 13, 2023

Conversation

zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Oct 16, 2023

Closes #61460.

We have FunctionParmPackExpr that serves as the unexpanded expression but from which the visitor collects none, which may lead to assertion failure during the template instantiation.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 16, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 16, 2023

@llvm/pr-subscribers-clang

Author: None (zyn0217)

Changes

…ctUnexpandedParameterPacksVisitor

Closes #61460.

We have FunctionParmPackExpr that serves as the unexpanded expression but from which the visitor collects none, which may lead to assertion failure during the template instantiation.

Actually, we don't need to assert this condition since we would do nothing in the subsequent DiagnoseUnexpandedParameterPacks call even if unsatisfied.


Full diff: https://github.com/llvm/llvm-project/pull/69224.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/lib/Sema/SemaTemplateVariadic.cpp (+6-12)
  • (added) clang/test/SemaCXX/pr61460.cpp (+8)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9782c123f4c9372..0c70ddf0e9a8b1e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -397,6 +397,8 @@ Bug Fixes in This Version
   operator in C. No longer issuing a confusing diagnostic along the lines of
   "incompatible operand types ('foo' and 'foo')" with extensions such as matrix
   types. Fixes (`#69008 <https://github.com/llvm/llvm-project/issues/69008>`_)
+- Fixed an issue that a benign assertion might hit when instantiating a pack expansion
+  inside a lambda. (`#61460 <https://github.com/llvm/llvm-project/issues/61460>`_)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index dfcc78dafdc4c31..b8912b2ad8a372d 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -388,9 +388,8 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
     return false;
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-  CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
-                                                              T->getTypeLoc());
-  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
+  CollectUnexpandedParameterPacksVisitor(Unexpanded)
+      .TraverseTypeLoc(T->getTypeLoc());
   return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
 }
 
@@ -404,7 +403,6 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
-  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
   return DiagnoseUnexpandedParameterPacks(E->getBeginLoc(), UPPC, Unexpanded);
 }
 
@@ -442,8 +440,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
-    .TraverseNestedNameSpecifier(SS.getScopeRep());
-  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
+      .TraverseNestedNameSpecifier(SS.getScopeRep());
   return DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
                                           UPPC, Unexpanded);
 }
@@ -479,8 +476,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
-    .TraverseType(NameInfo.getName().getCXXNameType());
-  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
+      .TraverseType(NameInfo.getName().getCXXNameType());
   return DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
 }
 
@@ -493,8 +489,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
-    .TraverseTemplateName(Template);
-  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
+      .TraverseTemplateName(Template);
   return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
 }
 
@@ -506,8 +501,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   CollectUnexpandedParameterPacksVisitor(Unexpanded)
-    .TraverseTemplateArgumentLoc(Arg);
-  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
+      .TraverseTemplateArgumentLoc(Arg);
   return DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
 }
 
diff --git a/clang/test/SemaCXX/pr61460.cpp b/clang/test/SemaCXX/pr61460.cpp
new file mode 100644
index 000000000000000..ee9d1db4bb09486
--- /dev/null
+++ b/clang/test/SemaCXX/pr61460.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++17 %s -fsyntax-only -verify
+// expected-no-diagnostics
+template <typename... Ts> void g(Ts... p1s) {
+  (void)[&](auto... p2s) { ([&] { p1s; p2s; }, ...); };
+}                                                       
+void f1() {
+  g();
+}

@erichkeane
Copy link
Collaborator

@cor3ntin : Lambda stuff, I think you're more familiar than I am with this. Mind taking a pass?

@cor3ntin
Copy link
Contributor

I think the issue here is that we make the assumption that a full expression cannot contain an unexpanded pack
But that does not hold for lambda.

Maybe instead of removing the assert entirely we could check whether one of the enclosing scope is a lambda.

While I think the change would be correct, i also think the assert is useful and I'm a bit concerned that removing it entirely will create problems down the line.

so i would encouraging researching

assert((!Unexpanded.empty() || enclosedInAnOtherExpression()) && "Unable to find unexpanded parameter packs");

where enclosedInAnOtherExpression would try to check that we are in a lambda - maybe Sema::getEnclosingLambda() is sufficient - not sure though.

Can we run into similar problems with statement expressions ? (I don't think so as they don't have parameter or capture list)

@zyn0217
Copy link
Contributor Author

zyn0217 commented Oct 21, 2023

Sorry for my late update - I've had a busy week ;)

I don't think so as they don't have parameter or capture list

+1. and it looks like we don't allow expanding a pack outside a statement expression, which more or less prevents the appearance of FunctionParmPackExpr.

so i would encouraging researching

assert((!Unexpanded.empty() || enclosedInAnOtherExpression()) && "Unable to find unexpanded parameter packs");

where enclosedInAnOtherExpression would try to check that we are in a lambda - maybe Sema::getEnclosingLambda() is sufficient - not sure though.

Instead of putting it inside an assertion, how about adding a check for FunctionParmPackExpr separately? I mean,

if (auto *Expr = dyn_cast<FunctionParmPackExpr>(E); Expr && getEnclosingLambda())
  return false;

to bail out only inside the Expr overload of DiagnoseUnexpandedParameterPack. (since it's the one being called anyways during template instantiation.)

@zyn0217 zyn0217 changed the title [clang][Sema] Don't assert non-empty unexpanded packs following Colle… [clang][Sema] Avoid non-empty unexpanded pack assertion for FunctionParmPackExpr Oct 21, 2023
@cor3ntin
Copy link
Contributor

Instead of putting it inside an assertion, how about adding a check for FunctionParmPackExpr separately? I mean,

If that works it would be fine with me, yes

@zyn0217 zyn0217 force-pushed the issue-61460 branch 2 times, most recently from 697d116 to 8cf9e71 Compare October 24, 2023 02:03
@cor3ntin
Copy link
Contributor

Looks generally good to me. can you remove the whitespace only changes? thanks!

@zyn0217
Copy link
Contributor Author

zyn0217 commented Oct 25, 2023

Done. Sorry for leaving irrelevant changes ;)

Comment on lines 405 to 414
// Exception: The `CollectUnexpandedParameterPacksVisitor` collects nothing
// from a FunctionParmPackExpr. In the context where the collector is being
// used such as `collectUnexpandedParameterPacks`, this type of expression
// is not expected to be collected.
//
// Nonetheless, this function for diagnosis is still called anyway during
// template instantiation, with an expression of such a type if we're inside a
// lambda with unexpanded parameters.
//
// Rule out this case to prevent the assertion failure.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Exception: The `CollectUnexpandedParameterPacksVisitor` collects nothing
// from a FunctionParmPackExpr. In the context where the collector is being
// used such as `collectUnexpandedParameterPacks`, this type of expression
// is not expected to be collected.
//
// Nonetheless, this function for diagnosis is still called anyway during
// template instantiation, with an expression of such a type if we're inside a
// lambda with unexpanded parameters.
//
// Rule out this case to prevent the assertion failure.
// CollectUnexpandedParameterPacksVisitor does not expect to see a FunctionParmPackExpr, but
// diagnosing unexpected parameter packs may still see such an expression in a lambda body. We'll
// bail out early in this case to avoid triggering an assertion.

Slight rewording.

…armPackExpr

Closes llvm#61460.

We have FunctionParmPackExpr that serves as the unexpanded
expression but from which the visitor collects none, which may
lead to assertion failure during the template instantiation.
@zyn0217
Copy link
Contributor Author

zyn0217 commented Oct 31, 2023

Thank you folks for the suggestions! I've updated, PTAL. :-)

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks

@zyn0217 zyn0217 merged commit 868007a into llvm:main Nov 13, 2023
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
…armPackExpr (llvm#69224)

Closes llvm#61460.

We have FunctionParmPackExpr that serves as the unexpanded expression
but from which the visitor collects none, which may lead to assertion
failure during the template instantiation.
zyn0217 added a commit to zyn0217/llvm-project that referenced this pull request Mar 23, 2024
…edParameterPack

This is a follow-up for llvm#69224,
where the previous fix failed to handle the parentheses around the
expression.

Fixes llvm#86361.
zyn0217 added a commit that referenced this pull request Sep 9, 2024
`FunctionParmPackExpr`s are peculiar in that they have to be of
unexpanded dependency while they don't introduce any unexpanded packs.
So this patch rules them out in the non-empty pack assertion in
`DiagnoseUnexpandedParameterPack()`.

There was a fix #69224, but that turned out to be insufficient.

I also moved the separate tests to a pre-existing file.

Fixes #86361
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Assertion failure with nested parameter packs and lambdas
6 participants