[clang] [clang][Sema] Fix false-positive -Wshadow for friend functions (PR #221249)
ahmed mohamed kamel via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 06:57:21 PDT 2026
https://github.com/AhmedKamel10 updated https://github.com/llvm/llvm-project/pull/221249
>From 86319ac68e5acded16ec7fdbafc0e18e4d722be6 Mon Sep 17 00:00:00 2001
From: ahmedkamel10 <amkzaher at gmail.com>
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 <amkzaher at gmail.com>
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 <amkzaher at gmail.com>
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;
More information about the cfe-commits
mailing list