Skip to content
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 handling of placeholder variables name in init captures #107055

Merged
merged 2 commits into from
Sep 3, 2024

Conversation

cor3ntin
Copy link
Contributor

@cor3ntin cor3ntin commented Sep 3, 2024

We were incorrectly not deduplicating results when looking up _ which, for a lambda init capture, would result in an ambiguous lookup.

The same bug caused some diagnostic notes to be emitted twice.

Fixes #107024

We were incorrectly not deduplicating results when
looking up `_` which, for a lambda init capture, would result
in an ambiguous lookup.

The same bug caused some diagnostic notes to be emitted twice.

Fixes llvm#107024
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 3, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 3, 2024

@llvm/pr-subscribers-clang

Author: cor3ntin (cor3ntin)

Changes

We were incorrectly not deduplicating results when looking up _ which, for a lambda init capture, would result in an ambiguous lookup.

The same bug caused some diagnostic notes to be emitted twice.

Fixes #107024


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

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+1-1)
  • (modified) clang/test/SemaCXX/cxx2c-placeholder-vars.cpp (+4-2)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fc940db4813948..af4388eada8e5a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -339,6 +339,7 @@ Bug Fixes to C++ Support
 - Template parameter names are considered in the name lookup of out-of-line class template
   specialization right before its declaration context. (#GH64082)
 - Fixed a constraint comparison bug for friend declarations. (#GH78101)
+- Fix handling of ``_`` as the name of a lambda's init capture variable. (#GH107024)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 7a6a64529f52ec..d3d4bf27ae7283 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -570,7 +570,7 @@ void LookupResult::resolveKind() {
 
     // For non-type declarations, check for a prior lookup result naming this
     // canonical declaration.
-    if (!D->isPlaceholderVar(getSema().getLangOpts()) && !ExistingI) {
+    if (!ExistingI) {
       auto UniqueResult = Unique.insert(std::make_pair(D, I));
       if (!UniqueResult.second) {
         // We've seen this entity before.
diff --git a/clang/test/SemaCXX/cxx2c-placeholder-vars.cpp b/clang/test/SemaCXX/cxx2c-placeholder-vars.cpp
index 5cf66b48784e91..29ca3b5ef3df72 100644
--- a/clang/test/SemaCXX/cxx2c-placeholder-vars.cpp
+++ b/clang/test/SemaCXX/cxx2c-placeholder-vars.cpp
@@ -50,14 +50,16 @@ void f() {
 
 void lambda() {
     (void)[_ = 0, _ = 1] { // expected-warning {{placeholder variables are incompatible with C++ standards before C++2c}} \
-                           // expected-note 4{{placeholder declared here}}
+                           // expected-note 2{{placeholder declared here}}
         (void)_++; // expected-error {{ambiguous reference to placeholder '_', which is defined multiple times}}
     };
 
     {
         int _ = 12;
-        (void)[_ = 0]{}; // no warning (different scope)
+        (void)[_ = 0]{ return _;}; // no warning (different scope)
     }
+
+    auto GH107024 = [_ = 42]() { return _; }();
 }
 
 namespace global_var {

Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

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

One thing I'm not entirely clear about is why we would end up with two same placeholder Decls in LookupResult.

It seems that IdResolver results in two same duplicate Decls for such case, but I don't know why.

(However I'd still approve it because this reverts the condition to the state before the placeholder patch.)

@zyn0217
Copy link
Contributor

zyn0217 commented Sep 3, 2024

I took a cursory look, and it seems that we pushed the same init capture to the scope chain three times:

  1. Sema::ActOnLambdaExpressionAfterIntroducer

    if (auto *V = dyn_cast<VarDecl>(Var))
    CheckShadow(CurrentScope, V);
    PushOnScopeChains(Var, CurrentScope, false);

  2. Sema::ActOnLambdaExpressionAfterIntroducer

if (C->Init.isUsable()) {
addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef);
PushOnScopeChains(Var, CurScope, false);
} else {

  1. Sema::ActOnStartOfLambdaDefinition
    for (auto &&C : LSI->Captures) {
    if (!C.isVariableCapture())
    continue;
    ValueDecl *Var = C.getVariable();
    if (Var && Var->isInitCapture()) {
    PushOnScopeChains(Var, CurScope, false);
    }
    }

I'm confused if they're all necessary...

@@ -1323,7 +1323,6 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,

if (C->Init.isUsable()) {
addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef);
PushOnScopeChains(Var, CurScope, false);
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, 2 is a duplicate of 1, but 3 is necessary because that constitutes a lambda body scope.

@cor3ntin
Copy link
Contributor Author

cor3ntin commented Sep 3, 2024

The second was clearly duplicated.
The first one introduce a scope for the captures, so that captures are available in the declaration of the lambda (before its compound statement).

But the body introduces a new scope wherein we inject the parameters - and we also need to reinject the captures to make sure they cannot be shadowed by a local variables

[a = 0] 
// capture scope
{
 // body scope
 int a = 42; // error!
}```

@cor3ntin
Copy link
Contributor Author

cor3ntin commented Sep 3, 2024

Should we backport this?

@zyn0217
Copy link
Contributor

zyn0217 commented Sep 3, 2024

I think so, yes.

@cor3ntin cor3ntin merged commit eec1fac into llvm:main Sep 3, 2024
9 checks passed
@cor3ntin cor3ntin added this to the LLVM 19.X Release milestone Sep 3, 2024
@cor3ntin
Copy link
Contributor Author

cor3ntin commented Sep 3, 2024

/cherry-pick eec1fac

@cor3ntin cor3ntin deleted the corentin/gh107024 branch September 3, 2024 18:37
@llvmbot
Copy link
Member

llvmbot commented Sep 3, 2024

Failed to cherry-pick: eec1fac

https://github.com/llvm/llvm-project/actions/runs/10688677657

Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request

cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Sep 4, 2024
…lvm#107055)

We were incorrectly not deduplicating results when looking up `_` which,
for a lambda init capture, would result in an ambiguous lookup.

The same bug caused some diagnostic notes to be emitted twice.

Fixes llvm#107024
@nikic
Copy link
Contributor

nikic commented Sep 4, 2024

For reference, the manual cherry pick is #107214.

cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Sep 12, 2024
…lvm#107055)

We were incorrectly not deduplicating results when looking up `_` which,
for a lambda init capture, would result in an ambiguous lookup.

The same bug caused some diagnostic notes to be emitted twice.

Fixes llvm#107024
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
Development

Successfully merging this pull request may close these issues.

[clang] "error: ambiguous reference to placeholder" when '_' is used as identifier in lambda capture
4 participants