https://github.com/aaditya8979 created https://github.com/llvm/llvm-project/pull/237624
Fixes #237332. When a method is declared with a parenthesised name and a trailing return type (e.g. `auto (operator++)() & -> S &`), the TypeLoc wraps FunctionTypeLoc inside a ParenTypeLoc. getAs<FunctionTypeLoc>() does not look through ParenTypeLoc, hitting the assert. Fix: use getAsAdjusted<FunctionTypeLoc>() which strips wrapping type locs. Also guard findPreviousToken()'s optional return before dereferencing. I used AI tools (Google Gemini) for assistance with parts of this patch. >From cbaac8b456458902fde945686eb306eb3b6d73f8 Mon Sep 17 00:00:00 2001 From: openhands <[email protected]> Date: Sun, 1 Nov 2026 01:15:44 +0530 Subject: [PATCH] [clang][LifetimeSafety] Fix crash in getLifetimeBoundFixIt for parenthesised declarators TypeLoc::getAs<FunctionTypeLoc>() does not look through ParenTypeLoc, so a method declared as 'auto (operator++)() & -> S &' caused an assertion failure in getLifetimeBoundFixIt(). Switch to getAsAdjusted<FunctionTypeLoc>() which strips wrapping type locs including ParenTypeLoc. Also guard the findPreviousToken() optional result before dereferencing it. Fixes #237332 --- clang/lib/Sema/SemaLifetimeSafety.h | 21 ++++++++++------ .../LifetimeSafety/paren-decl-no-crash.cpp | 25 +++++++++++++++++++ 2 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 clang/test/Sema/LifetimeSafety/paren-decl-no-crash.cpp diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 0df2ae84f92742..7a5c52dd17b5ff 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -715,14 +715,19 @@ class LifetimeSafetySemaHelperImpl final : public LifetimeSafetySemaHelper { // after '->', placing the attribute in an invalid position. // Instead use 'getLocalRangeEnd()' which gives the '->' location // for trailing returns, so find the last token before it. - const auto FTL = MDL.getAs<FunctionTypeLoc>(); - assert(FTL); - InsertionPoint = Lexer::getLocForEndOfToken( - Lexer::findPreviousToken(FTL.getLocalRangeEnd(), S.getSourceManager(), - S.getLangOpts(), - /*IncludeComments=*/false) - ->getLocation(), - 0, S.getSourceManager(), S.getLangOpts()); + // A parenthesised declarator (e.g. 'auto (f)() & -> T') wraps the + // FunctionTypeLoc inside a ParenTypeLoc. getAs<> does not look through + // ParenTypeLoc, so use getAsAdjusted<> which strips qualifying wrappers. + const auto FTL = MDL.getAsAdjusted<FunctionTypeLoc>(); + if (!FTL) + return {InsertionPoint, + getLifetimeBoundFixItText(InsertionPoint, /*LeadingSpace=*/true, + /*AllowGNUAttrMacro=*/false)}; + if (auto PrevTok = Lexer::findPreviousToken( + FTL.getLocalRangeEnd(), S.getSourceManager(), S.getLangOpts(), + /*IncludeComments=*/false)) + InsertionPoint = Lexer::getLocForEndOfToken( + PrevTok->getLocation(), 0, S.getSourceManager(), S.getLangOpts()); } return {InsertionPoint, getLifetimeBoundFixItText(InsertionPoint, /*LeadingSpace=*/true, diff --git a/clang/test/Sema/LifetimeSafety/paren-decl-no-crash.cpp b/clang/test/Sema/LifetimeSafety/paren-decl-no-crash.cpp new file mode 100644 index 00000000000000..ffabd630a8a024 --- /dev/null +++ b/clang/test/Sema/LifetimeSafety/paren-decl-no-crash.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++17 -flifetime-safety-inference \ +// RUN: -fexperimental-lifetime-safety-tu-analysis \ +// RUN: -Wlifetime-safety-suggestions -Wno-dangling -verify %s + +// Verify that parenthesised declarator names with trailing return types don't +// crash the lifetimebound fixit suggestion logic. getLifetimeBoundFixIt() for +// CXXMethodDecl used TypeLoc::getAs<FunctionTypeLoc>() to navigate into the +// type, but parenthesised declarators (e.g. 'auto (f)() & -> T') wrap the +// FunctionTypeLoc inside a ParenTypeLoc which getAs<> cannot see through. +// +// https://github.com/llvm/llvm-project/issues/237332 + +struct S { + // Crash: parenthesised operator name + trailing return type. + auto (operator++)() & -> S & { return *this; } // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}} + // expected-note@-1 {{param returned here}} + + // Parenthesised operator name, conventional (non-trailing) return type. + S & (operator--)(int) { return *this; } // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}} + // expected-note@-1 {{param returned here}} + + // Non-parenthesised trailing return -- was already working, must stay so. + auto operator++(int) -> S & { return *this; } // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}} + // expected-note@-1 {{param returned here}} +}; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
