llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Aaditya Agarwal (aaditya8979)

<details>
<summary>Changes</summary>

Fixes #<!-- -->237332.

When a method is declared with a parenthesised name and a trailing return
type (e.g. `auto (operator++)() &amp; -&gt; S &amp;`), the TypeLoc wraps
FunctionTypeLoc inside a ParenTypeLoc.  getAs&lt;FunctionTypeLoc&gt;() does not
look through ParenTypeLoc, hitting the assert.

Fix: use getAsAdjusted&lt;FunctionTypeLoc&gt;() 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.

---
Full diff: https://github.com/llvm/llvm-project/pull/237624.diff


2 Files Affected:

- (modified) clang/lib/Sema/SemaLifetimeSafety.h (+13-8) 
- (added) clang/test/Sema/LifetimeSafety/paren-decl-no-crash.cpp (+25) 


``````````diff
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}}
+};

``````````

</details>


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

Reply via email to