From be0905a333d6f7c4d7f5c70c18211463e53473cd Mon Sep 17 00:00:00 2001 From: Jun Zhang Date: Fri, 15 Apr 2022 15:14:38 +0800 Subject: [PATCH] [Clang][Sema] Fix invalid redefinition error in if/switch/for statement Clang should no longer incorrectly diagnose a variable declaration inside of a lambda expression that shares the name of a variable in a containing if/while/for/switch init statement as a redeclaration. After this patch, clang is supposed to accept code below: void foo() { for (int x = [] { int x = 0; return x; }(); ;) ; } Fixes https://github.com/llvm/llvm-project/issues/54913 Differential Revision: https://reviews.llvm.org/D123840 --- clang/docs/ReleaseNotes.rst | 4 ++++ clang/lib/Sema/IdentifierResolver.cpp | 5 ++++- clang/test/SemaCXX/cxx1z-init-statement.cpp | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f5d3793..2497280 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -119,6 +119,10 @@ Bug Fixes This fixes Issue `Issue 52802 `_. - Unknown type attributes with a ``[[]]`` spelling are no longer diagnosed twice. This fixes Issue `Issue 54817 `_. +- Clang should no longer incorrectly diagnose a variable declaration inside of + a lambda expression that shares the name of a variable in a containing + if/while/for/switch init statement as a redeclaration. + This fixes `Issue 54913 `_. Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index 333f4d7..9c5d78f 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -121,7 +121,10 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S, // of the controlled statement. // assert(S->getParent() && "No TUScope?"); - if (S->getParent()->getFlags() & Scope::ControlScope) { + // If the current decl is in a lambda, we shouldn't consider this is a + // redefinition as lambda has its own scope. + if (S->getParent()->getFlags() & Scope::ControlScope && + !S->isFunctionScope()) { S = S->getParent(); if (S->isDeclScope(D)) return true; diff --git a/clang/test/SemaCXX/cxx1z-init-statement.cpp b/clang/test/SemaCXX/cxx1z-init-statement.cpp index eea2589..b963c9e 100644 --- a/clang/test/SemaCXX/cxx1z-init-statement.cpp +++ b/clang/test/SemaCXX/cxx1z-init-statement.cpp @@ -90,3 +90,18 @@ void test_constexpr_init_stmt() { static_assert(constexpr_switch_init(-2) == 0, ""); static_assert(constexpr_switch_init(-5) == -1, ""); } + +int test_lambda_init() { + if (int x = []() {int x = 42; return x; }(); x) { + }; + + switch (int y = []() {int y = 42; return y; }(); y) { + case 42: + return 1; + } + + for (int x = [] { int x = 0; return x; }();;) + ; + + return 0; +} -- 2.7.4