[clang] [Clang] fix overload resolution for object parameters with top-level cv-qualifiers in member functions (PR #110435)

Oleksandr T. via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 9 08:58:44 PDT 2024


https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/110435

>From c52634882631a71fad956a70179b480abf13006a Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Sun, 29 Sep 2024 22:01:38 +0300
Subject: [PATCH 1/3] [Clang] fix overload resolution for object parameters
 with top-level cv-qualifiers in member functions

---
 clang/docs/ReleaseNotes.rst                | 1 +
 clang/lib/Sema/SemaOverload.cpp            | 3 +++
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 7 +++++++
 3 files changed, 11 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 28c759538f7df6..1bec2838765dab 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -447,6 +447,7 @@ Bug Fixes to C++ Support
 - Fixed an assertion failure in debug mode, and potential crashes in release mode, when
   diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
 - Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326)
+- Fixed overload handling for object parameters with top-level cv-qualifiers in explicit member functions (#GH100394)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0c1e054f7c30a4..7c40bab70bbe9d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1511,6 +1511,9 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
       auto NewObjectType = New->getFunctionObjectParameterReferenceType();
       auto OldObjectType = Old->getFunctionObjectParameterReferenceType();
 
+      if (NewObjectType.isConstQualified() != OldObjectType.isConstQualified())
+        return false;
+
       auto IsImplicitWithNoRefQual = [](const CXXMethodDecl *F) {
         return F->getRefQualifier() == RQ_None &&
                !F->isExplicitObjectMemberFunction();
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 63bf92e8d5edd3..5fd02502ce6df4 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1073,3 +1073,10 @@ int main() {
   return foo[]; // expected-error {{no viable overloaded operator[] for type 'Foo'}}
 }
 }
+
+namespace GH100394 {
+struct C {
+  void f(this const C);
+  void f() const ;      // ok
+};
+}

>From d377c01f46acf28f1dc74103c6a26df6c0c2e376 Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Sun, 6 Oct 2024 11:52:48 +0300
Subject: [PATCH 2/3] adjust overload resolution for volatile qualifiers

---
 clang/lib/Sema/SemaOverload.cpp            |  7 +++++--
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 12 +++++++++---
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 7c40bab70bbe9d..56705971517cc3 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1511,8 +1511,11 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
       auto NewObjectType = New->getFunctionObjectParameterReferenceType();
       auto OldObjectType = Old->getFunctionObjectParameterReferenceType();
 
-      if (NewObjectType.isConstQualified() != OldObjectType.isConstQualified())
-        return false;
+      if (Old->isExplicitObjectMemberFunction() &&
+          OldObjectType.getQualifiers() != NewObjectType.getQualifiers())
+        return OldObjectType.isConstQualified() &&
+               (NewObjectType.isConstQualified() ||
+                NewObjectType.isVolatileQualified());
 
       auto IsImplicitWithNoRefQual = [](const CXXMethodDecl *F) {
         return F->getRefQualifier() == RQ_None &&
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 5fd02502ce6df4..7dcd63a587c708 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1075,8 +1075,14 @@ int main() {
 }
 
 namespace GH100394 {
-struct C {
-  void f(this const C);
-  void f() const ;      // ok
+struct C1 {
+  void f(this const C1);
+  void f() const;        // ok
+};
+
+struct C2 {
+  void f(this const C2);    // expected-note {{previous declaration is here}}
+  void f(this volatile C2); // expected-error {{class member cannot be redeclared}} \
+                            // expected-warning {{volatile-qualified parameter type 'volatile C2' is deprecated}}
 };
 }

>From d524f7c0556fa08bd93a48f1ac6edd754a12926a Mon Sep 17 00:00:00 2001
From: Oleksandr T <oleksandr.tarasiuk at outlook.com>
Date: Wed, 9 Oct 2024 02:46:48 +0300
Subject: [PATCH 3/3] adjust qualifier restrictions for overriding explicit
 object members

---
 clang/lib/Sema/SemaOverload.cpp            | 31 ++++++++++++++--------
 clang/test/SemaCXX/cxx2b-deducing-this.cpp | 21 +++++++++++----
 2 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 95db7a4305cc87..c1799dfd2bc163 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1422,8 +1422,14 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
   // the implicit object parameter are of the same type.
 
   auto NormalizeQualifiers = [&](const CXXMethodDecl *M, Qualifiers Q) {
-    if (M->isExplicitObjectMemberFunction())
+    if (M->isExplicitObjectMemberFunction()) {
+      if (M->getNumParams() > 0) {
+        auto ThisType = M->getParamDecl(0)->getType().getCanonicalType();
+        if (ThisType.isConstQualified())
+          Q.removeConst();
+      }
       return Q;
+    }
 
     // We do not allow overloading based off of '__restrict'.
     Q.removeRestrict();
@@ -1439,14 +1445,23 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
     return Q;
   };
 
-  auto CompareType = [&](QualType Base, QualType D) {
-    auto BS = Base.getNonReferenceType().getCanonicalType().split();
+  auto AreQualifiersEqual = [&](SplitQualType BS, SplitQualType DS) {
     BS.Quals = NormalizeQualifiers(OldMethod, BS.Quals);
+    DS.Quals = NormalizeQualifiers(NewMethod, DS.Quals);
+
+    if (OldMethod->isExplicitObjectMemberFunction()) {
+      BS.Quals.removeVolatile();
+      DS.Quals.removeVolatile();
+    }
 
+    return BS.Quals == DS.Quals;
+  };
+
+  auto CompareType = [&](QualType Base, QualType D) {
+    auto BS = Base.getNonReferenceType().getCanonicalType().split();
     auto DS = D.getNonReferenceType().getCanonicalType().split();
-    DS.Quals = NormalizeQualifiers(NewMethod, DS.Quals);
 
-    if (BS.Quals != DS.Quals)
+    if (!AreQualifiersEqual(BS, DS))
       return false;
 
     if (OldMethod->isImplicitObjectMemberFunction() &&
@@ -1511,12 +1526,6 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
       auto NewObjectType = New->getFunctionObjectParameterReferenceType();
       auto OldObjectType = Old->getFunctionObjectParameterReferenceType();
 
-      if (Old->isExplicitObjectMemberFunction() &&
-          OldObjectType.getQualifiers() != NewObjectType.getQualifiers())
-        return OldObjectType.isConstQualified() &&
-               (NewObjectType.isConstQualified() ||
-                NewObjectType.isVolatileQualified());
-
       auto IsImplicitWithNoRefQual = [](const CXXMethodDecl *F) {
         return F->getRefQualifier() == RQ_None &&
                !F->isExplicitObjectMemberFunction();
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 7dcd63a587c708..2a984a75f37d21 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -142,8 +142,8 @@ struct Corresponding {
     void d(this Corresponding&&);
     void d(this const Corresponding&);
     void d(this const int&);
-    void d(this const int);
-    void d(this int);
+    void d(this const int);  // expected-note {{previous declaration is here}}
+    void d(this int);        // expected-error {{class member cannot be redeclared}}
 
     void e(this const Corresponding&&); // expected-note {{here}}
     void e() const &&; // expected-error{{cannot be redeclared}}
@@ -171,9 +171,8 @@ struct CorrespondingTpl {
     void d(this Corresponding&&);
     void d(this const Corresponding&);
     void d(this const int&);
-    void d(this const int);
-    void d(this int);
-
+    void d(this const int); // expected-note {{previous declaration is here}}
+    void d(this int);       // expected-error {{class member cannot be redeclared}}
     void e(this const CorrespondingTpl&&); // expected-note {{here}}
     void e() const &&; // expected-error{{cannot be redeclared}}
 };
@@ -1085,4 +1084,16 @@ struct C2 {
   void f(this volatile C2); // expected-error {{class member cannot be redeclared}} \
                             // expected-warning {{volatile-qualified parameter type 'volatile C2' is deprecated}}
 };
+
+struct C3 {
+  void f(this volatile C3); // expected-note {{previous declaration is here}} \
+                            // expected-warning {{volatile-qualified parameter type 'volatile C3' is deprecated}}
+  void f(this const C3);    // expected-error {{class member cannot be redeclared}}
+};
+
+struct C4 {
+  void f(this const C4);          // expected-note {{previous declaration is here}}
+  void f(this const volatile C4); // expected-error {{class member cannot be redeclared}} \
+                                  // expected-warning {{volatile-qualified parameter type 'const volatile C4' is deprecated}}
+};
 }



More information about the cfe-commits mailing list