https://github.com/AhmedKamel10 updated https://github.com/llvm/llvm-project/pull/221249
>From 86319ac68e5acded16ec7fdbafc0e18e4d722be6 Mon Sep 17 00:00:00 2001 From: ahmedkamel10 <[email protected]> Date: Fri, 4 Sep 2026 18:11:08 +0300 Subject: [PATCH 1/3] [clang][Sema] Fix false-positive -Wshadow for friend functions A friend function defined inline in a class body has no implicit 'this', so a parameter with the same name as a field cannot actually shadow it. CheckShadow only exempted static members and members with an explicit object parameter (via a valid CXXMethodDecl cast); it never handled the case where the enclosing function isn't a member function at all, which silently fell through to the generic diagnostic. Extend the exemption to cover that case. Fixes #221190 --- clang/docs/ReleaseNotes.md | 2 ++ clang/lib/Sema/SemaDecl.cpp | 12 +++++------- clang/test/SemaCXX/warn-shadow.cpp | 11 +++++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 6a2201012693e..f03819ad9e97a 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -492,6 +492,8 @@ features cannot lower the translation-unit ABI level; `operator delete`, since such a delete expression never invokes the destructor. (#GH65524) +- Fixed a false-positive `-Wshadow` warning when a function parameter in an inline-defined friend function shares the name of a non-static class member variable. (#GH221190) + ### Improvements to Clang's time-trace ### Improvements to Coverage Mapping diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a9047f61a8bf5..0c65539e796ab 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8627,13 +8627,11 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, DeclContext *NewDC = D->getDeclContext(); if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) { - if (const auto *MD = - dyn_cast<CXXMethodDecl>(getFunctionLevelDeclContext())) { - // Fields aren't shadowed in C++ static members or in member functions - // with an explicit object parameter. - if (MD->isStatic() || MD->isExplicitObjectMemberFunction()) - return; - } + const auto *MD = dyn_cast<CXXMethodDecl>(getFunctionLevelDeclContext()); + // Fields aren't shadowed in C++ static members or in member functions + // with an explicit object parameter. + if (!MD || MD->isStatic() || MD->isExplicitObjectMemberFunction()) + return; // Fields shadowed by constructor parameters are a special case. Usually // the constructor initializes the field with the parameter. if (isa<CXXConstructorDecl>(NewDC)) diff --git a/clang/test/SemaCXX/warn-shadow.cpp b/clang/test/SemaCXX/warn-shadow.cpp index 98a235a73c7e5..766766e465bdf 100644 --- a/clang/test/SemaCXX/warn-shadow.cpp +++ b/clang/test/SemaCXX/warn-shadow.cpp @@ -90,6 +90,17 @@ class A { } }; +class FriendFunction { + int x; // expected-note {{previous declaration is here}} + + friend bool operator==(const FriendFunction &f, int x) { + return f.x == x; + } + + void test(int x) { // expected-warning {{declaration shadows a field of 'FriendFunction'}} + } +}; + struct path { using value_type = char; typedef char value_type2; >From 6092cb2b4e92afc2afe4059a578d8aabe7cb2597 Mon Sep 17 00:00:00 2001 From: ahmedkamel10 <[email protected]> Date: Fri, 11 Sep 2026 16:16:24 +0300 Subject: [PATCH 2/3] [clang][Sema] Distinguish friend functions from NSDMI-lambda context in -Wshadow --- clang/lib/Sema/SemaDecl.cpp | 15 ++++++++++----- clang/test/SemaCXX/warn-shadow.cpp | 10 ++++++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0c65539e796ab..80e358e9f1c33 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8627,11 +8627,16 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, DeclContext *NewDC = D->getDeclContext(); if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) { - const auto *MD = dyn_cast<CXXMethodDecl>(getFunctionLevelDeclContext()); - // Fields aren't shadowed in C++ static members or in member functions - // with an explicit object parameter. - if (!MD || MD->isStatic() || MD->isExplicitObjectMemberFunction()) - return; + DeclContext *FnDC = getFunctionLevelDeclContext(); + if (const auto *MD = dyn_cast<CXXMethodDecl>(FnDC)) { + if (MD->isStatic() || MD->isExplicitObjectMemberFunction()) + return; + + } + else if (isa<FunctionDecl>(FnDC)) { + return; + } + // Fields shadowed by constructor parameters are a special case. Usually // the constructor initializes the field with the parameter. if (isa<CXXConstructorDecl>(NewDC)) diff --git a/clang/test/SemaCXX/warn-shadow.cpp b/clang/test/SemaCXX/warn-shadow.cpp index 766766e465bdf..30dac1bb67dec 100644 --- a/clang/test/SemaCXX/warn-shadow.cpp +++ b/clang/test/SemaCXX/warn-shadow.cpp @@ -92,15 +92,21 @@ class A { class FriendFunction { int x; // expected-note {{previous declaration is here}} - friend bool operator==(const FriendFunction &f, int x) { return f.x == x; } - void test(int x) { // expected-warning {{declaration shadows a field of 'FriendFunction'}} } }; +struct NSDMILambda { + int a; // expected-note {{previous declaration is here}} + int x = [this] { + int a = 0; // expected-warning {{declaration shadows a field of 'NSDMILambda'}} + return a; + }(); +}; + struct path { using value_type = char; typedef char value_type2; >From c064bc4c17d9155fb029dc3449a510b5263ca065 Mon Sep 17 00:00:00 2001 From: ahmedkamel10 <[email protected]> Date: Fri, 11 Sep 2026 16:48:27 +0300 Subject: [PATCH 3/3] [clang][Sema] Distinguish friend functions from NSDMI-lambda context in -Wshadow --- clang/lib/Sema/SemaDecl.cpp | 15 ++++++--------- clang/test/SemaCXX/warn-shadow.cpp | 1 - 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 80e358e9f1c33..3dc6f9a9770ce 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8627,16 +8627,13 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, DeclContext *NewDC = D->getDeclContext(); if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) { - DeclContext *FnDC = getFunctionLevelDeclContext(); - if (const auto *MD = dyn_cast<CXXMethodDecl>(FnDC)) { - if (MD->isStatic() || MD->isExplicitObjectMemberFunction()) - return; - - } - else if (isa<FunctionDecl>(FnDC)) { + DeclContext *FnDC = getFunctionLevelDeclContext(); + if (const auto *MD = dyn_cast<CXXMethodDecl>(FnDC)) { + if (MD->isStatic() || MD->isExplicitObjectMemberFunction()) return; - } - + } else if (isa<FunctionDecl>(FnDC)) { + return; + } // Fields shadowed by constructor parameters are a special case. Usually // the constructor initializes the field with the parameter. if (isa<CXXConstructorDecl>(NewDC)) diff --git a/clang/test/SemaCXX/warn-shadow.cpp b/clang/test/SemaCXX/warn-shadow.cpp index 30dac1bb67dec..fc184e5a1eb90 100644 --- a/clang/test/SemaCXX/warn-shadow.cpp +++ b/clang/test/SemaCXX/warn-shadow.cpp @@ -106,7 +106,6 @@ struct NSDMILambda { return a; }(); }; - struct path { using value_type = char; typedef char value_type2; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
