[clang] [Clang] Disallow explicit object parameters irrespective of whether return type is valid (PR #174603)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 6 07:04:28 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Kartik (hax0kartik)
<details>
<summary>Changes</summary>
This fixes issue: #<!-- -->173943
---
Full diff: https://github.com/llvm/llvm-project/pull/174603.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+1)
- (modified) clang/lib/Sema/SemaType.cpp (+58-57)
- (modified) clang/test/SemaCXX/cxx2b-deducing-this.cpp (+11)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 411cc348d4caf..b95b4ee65282f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -594,6 +594,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..46b668b7e0c0a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -4834,66 +4834,67 @@ 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/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 at -1 {{unknown type name 'a'}}
+ // expected-error at -2 {{an explicit object parameter cannot appear in a non-member function}}
+ Bar(0);
+ Bar(); // expected-error {{no matching function for call to 'Bar'}}
+}
+
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/174603
More information about the cfe-commits
mailing list