Author: Kartik
Date: 2026-01-06T19:30:43Z
New Revision: 9c7b48e3adf5e96c98ffe71beb2d892ee0275e2c

URL: 
https://github.com/llvm/llvm-project/commit/9c7b48e3adf5e96c98ffe71beb2d892ee0275e2c
DIFF: 
https://github.com/llvm/llvm-project/commit/9c7b48e3adf5e96c98ffe71beb2d892ee0275e2c.diff

LOG: [Clang] Disallow explicit object parameters irrespective of whether return 
type is valid (#174603)

Fixes: #173943

Added: 
    clang/test/SemaCXX/crash-GH173943.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaType.cpp
    clang/test/SemaCXX/cxx2b-deducing-this.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8ef6564bd80e6..3f6b435175d6d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -595,6 +595,7 @@ Bug Fixes to C++ Support
   "initializing multiple members of union" coincide (#GH149985).
 - Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. 
(#GH152729)
 - Fix the parsing of variadic member functions when the ellipis immediately 
follows a default argument.(#GH153445)
+- Fix a crash when using an explicit object parameter in a non-member function 
with an invalid return type.(#GH173943)
 - Fixed a bug that caused ``this`` captured by value in a lambda with a 
dependent explicit object parameter to not be
   instantiated properly. (#GH154054)
 - Fixed a bug where our ``member-like constrained friend`` checking caused an 
incorrect analysis of lambda captures. (#GH156225)

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 7ef83433326ed..28bb352b16196 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -4834,66 +4834,65 @@ static TypeSourceInfo 
*GetFullTypeForDeclarator(TypeProcessingState &state,
       IsQualifiedFunction =
           FTI.hasMethodTypeQualifiers() || FTI.hasRefQualifier();
 
+      auto IsClassType = [&](CXXScopeSpec &SS) {
+        // If there already was an problem with the scope, don’t issue another
+        // error about the explicit object parameter.
+        return SS.isInvalid() ||
+               isa_and_present<CXXRecordDecl>(S.computeDeclContext(SS));
+      };
+
+      // C++23 [dcl.fct]p6:
+      //
+      // An explicit-object-parameter-declaration is a parameter-declaration
+      // with a this specifier. An explicit-object-parameter-declaration shall
+      // appear only as the first parameter-declaration of a
+      // parameter-declaration-list of one of:
+      //
+      // - a declaration of a member function or member function template
+      //   ([class.mem]), or
+      //
+      // - an explicit instantiation ([temp.explicit]) or explicit
+      //   specialization ([temp.expl.spec]) of a templated member function,
+      //   or
+      //
+      // - a lambda-declarator [expr.prim.lambda].
+      DeclaratorContext C = D.getContext();
+      ParmVarDecl *First =
+          FTI.NumParams ? dyn_cast_if_present<ParmVarDecl>(FTI.Params[0].Param)
+                        : nullptr;
+
+      bool IsFunctionDecl = D.getInnermostNonParenChunk() == &DeclType;
+      if (First && First->isExplicitObjectParameter() &&
+          C != DeclaratorContext::LambdaExpr &&
+
+          // Either not a member or nested declarator in a member.
+          //
+          // Note that e.g. 'static' or 'friend' declarations are accepted
+          // here; we diagnose them later when we build the member function
+          // because it's easier that way.
+          (C != DeclaratorContext::Member || !IsFunctionDecl) &&
+
+          // Allow out-of-line definitions of member functions.
+          !IsClassType(D.getCXXScopeSpec())) {
+        if (IsFunctionDecl)
+          S.Diag(First->getBeginLoc(),
+                 diag::err_explicit_object_parameter_nonmember)
+              << /*non-member*/ 2 << /*function*/ 0 << First->getSourceRange();
+        else
+          S.Diag(First->getBeginLoc(),
+                 diag::err_explicit_object_parameter_invalid)
+              << First->getSourceRange();
+
+        // Do let non-member function have explicit parameters
+        // to not break assumptions elsewhere in the code.
+        First->setExplicitObjectParameterLoc(SourceLocation());
+        D.setInvalidType();
+        AreDeclaratorChunksValid = false;
+      }
+
       // Check for auto functions and trailing return type and adjust the
       // return type accordingly.
       if (!D.isInvalidType()) {
-        auto IsClassType = [&](CXXScopeSpec &SS) {
-          // If there already was an problem with the scope, don’t issue 
another
-          // error about the explicit object parameter.
-          return SS.isInvalid() ||
-                 isa_and_present<CXXRecordDecl>(S.computeDeclContext(SS));
-        };
-
-        // C++23 [dcl.fct]p6:
-        //
-        // An explicit-object-parameter-declaration is a parameter-declaration
-        // with a this specifier. An explicit-object-parameter-declaration 
shall
-        // appear only as the first parameter-declaration of a
-        // parameter-declaration-list of one of:
-        //
-        // - a declaration of a member function or member function template
-        //   ([class.mem]), or
-        //
-        // - an explicit instantiation ([temp.explicit]) or explicit
-        //   specialization ([temp.expl.spec]) of a templated member function,
-        //   or
-        //
-        // - a lambda-declarator [expr.prim.lambda].
-        DeclaratorContext C = D.getContext();
-        ParmVarDecl *First =
-            FTI.NumParams
-                ? dyn_cast_if_present<ParmVarDecl>(FTI.Params[0].Param)
-                : nullptr;
-
-        bool IsFunctionDecl = D.getInnermostNonParenChunk() == &DeclType;
-        if (First && First->isExplicitObjectParameter() &&
-            C != DeclaratorContext::LambdaExpr &&
-
-            // Either not a member or nested declarator in a member.
-            //
-            // Note that e.g. 'static' or 'friend' declarations are accepted
-            // here; we diagnose them later when we build the member function
-            // because it's easier that way.
-            (C != DeclaratorContext::Member || !IsFunctionDecl) &&
-
-            // Allow out-of-line definitions of member functions.
-            !IsClassType(D.getCXXScopeSpec())) {
-          if (IsFunctionDecl)
-            S.Diag(First->getBeginLoc(),
-                   diag::err_explicit_object_parameter_nonmember)
-                << /*non-member*/ 2 << /*function*/ 0
-                << First->getSourceRange();
-          else
-            S.Diag(First->getBeginLoc(),
-                   diag::err_explicit_object_parameter_invalid)
-                << First->getSourceRange();
-          // Do let non-member function have explicit parameters
-          // to not break assumptions elsewhere in the code.
-          First->setExplicitObjectParameterLoc(SourceLocation());
-          D.setInvalidType();
-          AreDeclaratorChunksValid = false;
-        }
-
         // trailing-return-type is only required if we're declaring a function,
         // and not, for instance, a pointer to a function.
         if (D.getDeclSpec().hasAutoTypeSpec() &&

diff  --git a/clang/test/SemaCXX/crash-GH173943.cpp 
b/clang/test/SemaCXX/crash-GH173943.cpp
new file mode 100644
index 0000000000000..e00a0f2fb12c9
--- /dev/null
+++ b/clang/test/SemaCXX/crash-GH173943.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++03 %s
+
+// https://github.com/llvm/llvm-project/issues/173943
+
+constexpr void f(this auto& self) // expected-note {{candidate function}}
+    // expected-error@-1 {{unknown type name 'constexpr'}}
+    // expected-error@-2 {{'auto' not allowed in function prototype}}
+    // expected-error@-3 {{explicit object parameters are incompatible with 
C++ standards before C++2b}}
+    // expected-error@-4 {{expected ';' after top level declarator}}
+    // expected-error@-5 {{an explicit object parameter cannot appear in a 
non-member function}}
+    // expected-warning@-6 {{'auto' type specifier is a C++11 extension}}
+
+void g() {
+  f(); // expected-error {{no matching function for call to 'f'}}
+}

diff  --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 6777dc23c44a6..a9e31c3d06676 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1389,3 +1389,14 @@ void f() {
 }
 
 }
+
+namespace GH173943 {
+
+a void Bar(this int) { // expected-note {{candidate function}}
+    // expected-error@-1 {{unknown type name 'a'}}
+    // expected-error@-2 {{an explicit object parameter cannot appear in a 
non-member function}}
+    Bar(0);
+    Bar(); // expected-error {{no matching function for call to 'Bar'}}
+}
+
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to