[clang] 48210cc - [LifetimeSafety] Correctly place lifetimebound attr in corner cases (#181699)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 01:54:24 PST 2026
Author: Baranov Victor
Date: 2026-02-17T12:54:20+03:00
New Revision: 48210ccbe58ef7b9799e1b9fc89edb2fe2ebc6bf
URL: https://github.com/llvm/llvm-project/commit/48210ccbe58ef7b9799e1b9fc89edb2fe2ebc6bf
DIFF: https://github.com/llvm/llvm-project/commit/48210ccbe58ef7b9799e1b9fc89edb2fe2ebc6bf.diff
LOG: [LifetimeSafety] Correctly place lifetimebound attr in corner cases (#181699)
Closes https://github.com/llvm/llvm-project/issues/180344.
Added:
Modified:
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/test/Sema/warn-lifetime-safety-fixits.cpp
clang/test/Sema/warn-lifetime-safety-suggestions.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 8c7bff27718de..5c49e601840cf 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2937,10 +2937,16 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
: diag::warn_lifetime_safety_intra_tu_param_suggestion;
SourceLocation InsertionPoint = Lexer::getLocForEndOfToken(
ParmToAnnotate->getEndLoc(), 0, S.getSourceManager(), S.getLangOpts());
+ StringRef FixItText = " [[clang::lifetimebound]]";
+ if (!ParmToAnnotate->getIdentifier()) {
+ // For unnamed parameters, placing attributes after the type would be
+ // parsed as a type attribute, not a parameter attribute.
+ InsertionPoint = ParmToAnnotate->getBeginLoc();
+ FixItText = "[[clang::lifetimebound]] ";
+ }
S.Diag(ParmToAnnotate->getBeginLoc(), DiagID)
<< ParmToAnnotate->getSourceRange()
- << FixItHint::CreateInsertion(InsertionPoint,
- " [[clang::lifetimebound]]");
+ << FixItHint::CreateInsertion(InsertionPoint, FixItText);
S.Diag(EscapeExpr->getBeginLoc(),
diag::note_lifetime_safety_suggestion_returned_here)
<< EscapeExpr->getSourceRange();
@@ -2952,10 +2958,24 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
unsigned DiagID = (Scope == SuggestionScope::CrossTU)
? diag::warn_lifetime_safety_cross_tu_this_suggestion
: diag::warn_lifetime_safety_intra_tu_this_suggestion;
- SourceLocation InsertionPoint;
- InsertionPoint = Lexer::getLocForEndOfToken(
- MD->getTypeSourceInfo()->getTypeLoc().getEndLoc(), 0,
- S.getSourceManager(), S.getLangOpts());
+ const auto MDL = MD->getTypeSourceInfo()->getTypeLoc();
+ SourceLocation InsertionPoint = Lexer::getLocForEndOfToken(
+ MDL.getEndLoc(), 0, S.getSourceManager(), S.getLangOpts());
+ if (const auto *FPT = MD->getType()->getAs<FunctionProtoType>();
+ FPT && FPT->hasTrailingReturn()) {
+ // For trailing return types, 'getEndLoc()' includes the return type
+ // 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());
+ }
S.Diag(InsertionPoint, DiagID)
<< MD->getNameInfo().getSourceRange()
<< FixItHint::CreateInsertion(InsertionPoint,
diff --git a/clang/test/Sema/warn-lifetime-safety-fixits.cpp b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
index 82b36caf8d141..3ae252a9d00f2 100644
--- a/clang/test/Sema/warn-lifetime-safety-fixits.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-fixits.cpp
@@ -138,3 +138,27 @@ const OutOfLine &OutOfLine::get() const {
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:40-[[@LINE-2]]:40}:" {{\[\[}}clang::lifetimebound]]"
return *this;
}
+
+struct TrailingReturn {
+ TrailingReturn() {}
+ ~TrailingReturn() {}
+ MyObj data;
+
+ auto get_view() -> View {
+ // CHECK: :[[@LINE-1]]:18: warning: implicit this in intra-TU function should be marked
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+
+ auto get_view_const() const -> View {
+ // CHECK: :[[@LINE-1]]:30: warning: implicit this in intra-TU function should be marked
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+
+ auto get_ref() const -> const MyObj & {
+ // CHECK: :[[@LINE-1]]:23: warning: implicit this in intra-TU function should be marked
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]"
+ return data;
+ }
+};
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 0ed545d06ca8a..1887b2f257226 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -50,6 +50,9 @@ inline View redeclared_in_header(View a) { // expected-warning {{parameter in i
return a; // expected-note {{param returned here}}
}
+View return_unnamed_view(View); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
+MyObj& return_unnamed_ref(MyObj&, bool); // expected-warning {{parameter in cross-TU function should be marked [[clang::lifetimebound]]}}
+
struct ReturnThis {
const ReturnThis& get() const; // expected-warning {{implicit this in cross-TU function should be marked [[clang::lifetimebound]]}}.
};
@@ -90,6 +93,14 @@ MyObj* return_pointer_object(MyObj* a) {
return a; // expected-note {{param returned here}}
}
+View return_unnamed_view(View a) {
+ return a; // expected-note {{param returned here}}
+}
+
+MyObj& return_unnamed_ref(MyObj& a, bool c) {
+ return a; // expected-note {{param returned here}}
+}
+
MyObj& return_reference(MyObj& a, // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
MyObj& b, // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
bool c) {
@@ -344,6 +355,26 @@ MyObj* test_template_inference_with_stack() {
}
} // namespace inference_with_templates
+namespace trailing_return {
+struct TrailingReturn {
+ TrailingReturn() {}
+ ~TrailingReturn() {}
+ MyObj data;
+
+ auto get_view() -> View { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
+ return data; // expected-note {{param returned here}}
+ }
+
+ auto get_view_const() const -> View { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
+ return data; // expected-note {{param returned here}}
+ }
+
+ auto get_ref() const -> const MyObj& { // expected-warning {{implicit this in intra-TU function should be marked [[clang::lifetimebound]]}}
+ return data; // expected-note {{param returned here}}
+ }
+};
+} // namespace trailing_return
+
//===----------------------------------------------------------------------===//
// Negative Test Cases
//===----------------------------------------------------------------------===//
More information about the cfe-commits
mailing list