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
