[clang] [llvm] [LifetimeSafety] Add lifetimebound inference for std::make_unique (PR #191632)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 15 12:05:58 PDT 2026
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/191632
>From 572e8aab9ccbdbcfea4ea548031a72be72fe17bf Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sat, 11 Apr 2026 13:11:00 +0000
Subject: [PATCH 01/16] Make Unique inference
---
a.o | Bin 0 -> 3448 bytes
.../LifetimeSafety/FactsGenerator.cpp | 3 +-
clang/lib/Analysis/LifetimeSafety/Origins.cpp | 1 +
clang/lib/Sema/SemaAttr.cpp | 55 ++++++++++++++
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +
clang/test/Sema/Inputs/lifetime-analysis.h | 3 +
.../Sema/warn-lifetime-analysis-nocfg.cpp | 11 +++
clang/test/Sema/warn-lifetime-safety.cpp | 68 +++++++++++++++++-
8 files changed, 139 insertions(+), 4 deletions(-)
create mode 100644 a.o
diff --git a/a.o b/a.o
new file mode 100644
index 0000000000000000000000000000000000000000..62582c83f3bfdb00d8640bee02912561d1d29b77
GIT binary patch
literal 3448
zcmb_eO>7%Q6dv16V$viHAqP+qq^J at _qMLP$9D-1B<ZQdpG(`C!qN3Vt)@#SqKa0I~
z+#;)$A|WhODToV*100aZp$Ei;8w9lojyV*mNE|Bhqe$i89*}YXnfG?*+2gg%1)enf
zX1;mzzVFS>j(ts;KkN7T7 at 3cqVXYCNjFp3}e$?qk**HY5s at 31r?LTDoMx}9pxLQ^A
z?=!Wg>_e{(@LlyrvF=O(3_~}n8NPj6zI02iep`k33kOx@*H)%l<-iGUG<?C}$+PU)
z=Na)u)oNu=tsVl$56}f)tbc>LxrXoExqZ-4S8FKhK&=(sbf~TfGnG9zxCSY<Z%08z
ztpXxkCHJbz&tJC^)++a$U<O)-V2jw9zBgFxMXrYn0J1~1cA>6TgO_eOdn7!Jw4O~)
zl+1h~mCH^{g(X>%lPP=R)TV7)g%>6#VX#@;kc?brGMz5DkJDB at _oivs5=Mq*!trT6
zq8sK+Vp<MGOgU`K$VMa_nTjOh8`Ft+VrFK;ke at -;aZc^Ky2O0tQQz^Qf#43*^Elwx
z&>q9b?8xXl{@8H;3IxEA=6qKd=be=UA7j*UT7MD-*wEt8j$ns!_-7%>>`?!x8#9k{
zVAr6v$E`KvaEtq)4M0PF91n6o1b!IWzu5;cd4xS^bc+cve>a!~Ts3WT!%nE9vJJ;U
zz){!%1CEN@?G6^u1xGaCREE8lJptV at K_~7h+SAZr8#^os`JWQ>;NGIW4y{|f+5`Wt
z2mVnH9LwsK|4T;?zA at LFGX>pGpmmFX0P!dM_-0+B9XtfQTRgpgd^5=MSHrbad_Cev
z1w1U^$U^b(sXB)7n3M1|7j{mBh_4Iyh!B55z>f*|O9GB{Q2qr0e^|it0zM|-Zwt7{
z%VFpHpl=(o2|j_xm-Z5&^8)?|@1tAieT)~sj+B50cpu%n0^TR!?+ZA7zhr~sM~{t-
zFzw<(WJS*>O*<A+mhDieVCPfWq*h9qTQK>YZ5HejMx9 at _Bkr70^28}lKy!XBL_kO`
zW>aq!P0h0NFLN5jnU?ZqT9<6IY%{z_GiDY#$$YM8F<mk&3mCIo8F<Fii=_;cvN_w7
z&MmB-F4($pnMru at YI-~lmvoY8tJ$qoHm)t1g<{5JZf<i^OXPJNCJjR~%Z6#$nyqi7
z0f9Q82mVUN at l7$3b`fjK=$B2+l}@r>S at IT*yCv4QqA7FMt1GhB$@o8|#qEMr3m#(H
z*w~b^xD52?VzIV*LwrZ#x~)rdYp^{DNz;<$vSz`LTrR7pQ}z|DBzG*7>8$)0|0gUK
z&ne}4jUUD*#lsDgaJ{ryg=6B`#egV2z~~-!N1b<587A;9iBbUfpCSmh<2r`l9!jBa
z^HGlf0v<JaWU|lreCvjE0iKr6GWH(y at ILX{b)Jy!Qsl?`k=BzR1ajo>_XzlcC#2sM
zKJ2)g`(Uw?%d=kQmjvz)8uH^Fd+T52{C at 9x6a_~5-BC+FjeFI<!}Adz^5Z^H-Q;g_
zesBFz&QHH%#OKx1i~mE;Pwx-;u at Nu%`<y at EsehgGlYZj&j(>+ZCzogaF5iDTXUL6O
zXg%TEfFYF(O|(tUpAkXmbGYe07cepOM+y|dF0ntknB|er?(+4!p7o at k;5*R4`lAGJ
zzsKv};bW{H-yN-|`o97!FyF|5yAG{si~K^MdjZ#@dCU46Ft2uu+vOnspFu<S5Hv6U
EKZPRj`v3p{
literal 0
HcmV?d00001
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 5adf842e5f6d0..0dee1c2c447cb 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -507,7 +507,8 @@ void FactsGenerator::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) {
hasOrigins(OCE->getArg(0)->getType())) {
// Pointer-like types: assignment inherently propagates origins.
QualType LHSTy = OCE->getArg(0)->getType();
- if (LHSTy->isPointerOrReferenceType() || isGslPointerType(LHSTy)) {
+ if (LHSTy->isPointerOrReferenceType() || isGslPointerType(LHSTy) ||
+ isGslOwnerType(LHSTy)) {
handleAssignment(OCE->getArg(0), OCE->getArg(1));
return;
}
diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
index 033cbdd75352c..37bd8a3ccc6bb 100644
--- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp
@@ -68,6 +68,7 @@ class LifetimeAnnotatedOriginTypeCollector
}
bool shouldVisitLambdaBody() const { return false; }
+ bool shouldVisitTemplateInstantiations() const { return true; }
const llvm::SmallVector<QualType> &getCollectedTypes() const {
return CollectedTypes;
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 7c79f954e6743..d173b1ba58d8e 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -250,6 +250,61 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
}
return;
}
+
+ // Handle std::make_unique to propagate lifetimebound attributes from the
+ // constructed type's constructor to make_unique's parameters.
+ if (FD->isInStdNamespace() && FD->getDeclName().isIdentifier() &&
+ FD->getName() == "make_unique") {
+ if (!FD->isFunctionTemplateSpecialization())
+ return;
+
+ const TemplateArgumentList *TAL = FD->getTemplateSpecializationArgs();
+ if (!TAL || TAL->size() < 1)
+ return;
+
+ // make_unique's first template argument is the type being constructed.
+ TemplateArgument TA = TAL->get(0);
+ if (TA.getKind() != TemplateArgument::Type)
+ return;
+
+ QualType T = TA.getAsType();
+ const auto *RD = T->getAsCXXRecordDecl();
+ if (!RD)
+ return;
+
+ // Find the constructor that matches make_unique's arguments.
+ for (const auto *Ctor : RD->ctors()) {
+ if (Ctor->getNumParams() != FD->getNumParams())
+ continue;
+
+ bool Compatible = true;
+ for (unsigned i = 0; i < Ctor->getNumParams(); ++i) {
+ QualType CtorParamType = Ctor->getParamDecl(i)->getType();
+ QualType FDParamType = FD->getParamDecl(i)->getType();
+ // Compare types ignoring references.
+ if (!Context.hasSameUnqualifiedType(
+ CtorParamType.getNonReferenceType(),
+ FDParamType.getNonReferenceType())) {
+ Compatible = false;
+ break;
+ }
+ }
+
+ if (!Compatible)
+ continue;
+ // Propagate lifetimebound attributes only if the constructor parameter is
+ // a reference. This avoids incorrect loan tracking when a by-value view
+ // (like string_view) is passed by reference to make_unique.
+ for (unsigned i = 0; i < Ctor->getNumParams(); ++i)
+ if (Ctor->getParamDecl(i)->hasAttr<LifetimeBoundAttr>() &&
+ Ctor->getParamDecl(i)->getType()->isReferenceType())
+ FD->getParamDecl(i)->addAttr(
+ LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+ break; // Found matching constructor, done.
+ }
+ return;
+ }
+
if (auto *CMD = dyn_cast<CXXMethodDecl>(FD)) {
const auto *CRD = CMD->getParent();
if (!CRD->isInStdNamespace() || !CRD->getIdentifier())
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 09c2482168ab7..954160d4112a5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5473,6 +5473,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,
LateAttrs, StartingScope);
+ SemaRef.inferLifetimeBoundAttribute(New);
+
return false;
}
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h
index 2b904f88bc475..3879f3e529bfc 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -205,6 +205,9 @@ struct unique_ptr {
T *get() const;
};
+template<typename T, typename... Args>
+unique_ptr<T> make_unique(Args&&... args);
+
template<typename T>
struct optional {
optional();
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 2b6c2d3d8bdb6..e07c90f248764 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -174,6 +174,17 @@ void initLocalGslPtrWithTempOwner() {
use(global2, p2); // cfg-note 2 {{later used here}}
}
+struct LifetimeBoundCtor {
+ LifetimeBoundCtor(const MyIntOwner& obj1 [[clang::lifetimebound]]);
+ LifetimeBoundCtor(std::string_view sv [[clang::lifetimebound]]);
+};
+
+auto lifetimebound_make_unique_single_param() {
+ return std::make_unique<LifetimeBoundCtor>(MyIntOwner{}); // expected-warning {{returning address of local temporary object}} \
+ // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
+}
+
+
struct Unannotated {
typedef std::vector<int>::iterator iterator;
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 082db5d5cbf15..9e4e3eca2117b 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -963,6 +963,68 @@ void lifetimebound_ctor_static_cast() {
(void)v; // expected-note {{later used here}}
}
+void lifetimebound_make_unique() {
+ std::unique_ptr<LifetimeBoundCtor> ptr;
+ {
+ MyObj obj;
+ ptr = std::make_unique<LifetimeBoundCtor>(obj); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+
+void lifetimebound_make_unique_temp() {
+ std::unique_ptr<LifetimeBoundCtor> ptr = std::make_unique<LifetimeBoundCtor>(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
+ // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+
+struct MultiLifetimeBoundCtor {
+ MultiLifetimeBoundCtor(const MyObj& obj1 [[clang::lifetimebound]], const MyObj& obj2);
+ MultiLifetimeBoundCtor(const MyObj& obj1, const MyObj& obj2 [[clang::lifetimebound]], int);
+ MultiLifetimeBoundCtor(const MyObj& obj1 [[clang::lifetimebound]], const MyObj& obj2 [[clang::lifetimebound]], double);
+ MultiLifetimeBoundCtor(std::string_view sv [[clang::lifetimebound]]);
+};
+
+void lifetimebound_make_unique_multi_params() {
+ std::unique_ptr<MultiLifetimeBoundCtor> ptr;
+ MyObj obj_long;
+ {
+ MyObj obj_short;
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+
+void lifetimebound_make_unique_multi_params2() {
+ std::unique_ptr<MultiLifetimeBoundCtor> ptr;
+ MyObj obj_long;
+ {
+ MyObj obj_short;
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+
+void lifetimebound_make_unique_multi_params3_1() {
+ std::unique_ptr<MultiLifetimeBoundCtor> ptr;
+ MyObj obj_long;
+ {
+ MyObj obj_short;
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+
+void lifetimebound_make_unique_multi_params3_2() {
+ std::unique_ptr<MultiLifetimeBoundCtor> ptr;
+ MyObj obj_long;
+ {
+ MyObj obj_short;
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+
View lifetimebound_return_of_local() {
MyObj stack;
return Identity(stack); // expected-warning {{address of stack memory is returned later}}
@@ -2452,9 +2514,9 @@ void owner_outlives_lifetimebound_source() {
std::unique_ptr<S> ups;
{
std::string local;
- ups = getUniqueS(local);
- }
- (void)ups; // Should warn.
+ ups = getUniqueS(local); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ups; // expected-note {{later used here}}
}
} // namespace track_origins_for_lifetimebound_record_type
>From d36d45be88cbcafa2a3e8a4e45eb4d45993ac2f2 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sat, 11 Apr 2026 13:26:11 +0000
Subject: [PATCH 02/16] string_view and pointer parameters
---
a.o | Bin 3448 -> 2984 bytes
clang/test/Sema/warn-lifetime-safety.cpp | 24 ++++++++++++++++++++++-
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/a.o b/a.o
index 62582c83f3bfdb00d8640bee02912561d1d29b77..6a53ddbada9cbc2494763f0d57e07746d0d02737 100644
GIT binary patch
literal 2984
zcmbVO&2Jl35P!DYBrQoWg#)M at T*Ltm-Po<;IDE;Gv&~Yat(7LCs#GoO_1bacFYLAB
z7DYsgRLQa;aX~_GK?o!c95`^{0z$3S9DD2^08%74gcCVLGV^=;rgk<qhmQ1iW`1uz
z-_Ab!Gky6=Fc1(-0r7$8Ym5r9Kh~F1QcQ`L$#Tu;{Auj`9eJ!D0X25 at Bcr1q7`t2h
z#%}Xq-vhVyJz?ij<jzCs%@5_DGCEs(M(2=xpO8qrdGH(R at ccTDy}hSKmtuFL68%dU
z-6kPhd!A93Tz4L&?mQ&usnPkpLy at lScl1Ag?FZ_rN<^<0m=p;i5~o+iyYF!|!s|yB
zK*<h`?zID>GvTY6?Cp|ODMVUMy-}=IB9|^}Q7u|1x{<fmUANYFXJ&?!^=4MHtL2$e
zspUN`*6P)}j_qo&%qM5(^SPumH&2wEwG*>ZJDarT;<LHAcs`m<M(ucRKH<EL>RwSL
z2JWwjKsy{bKRG_}Ira5A;aH%{cq~kZ9|Y4=V-+$W6?@#?YlHi%{e8fJ`<Z1KdHidr
z=Q;kHq+o$IX`O<=If6GR$in1UnEVMoO$%c(P7C at O#a|#kN$dY;kv30>e|p1gLLxW}
z79pAO<W@*la2zk9pdmQWkgOC^pJ0A&Ag?@I!p_jf8v}W9CZMyl=on7W)e-pm2z*J#
z$H{pl-x-M+TEpT$7==@u3qhQ`N0<fBF5$!CMC7jbeqnpm^GFUK>3Hv`it!61gMg!V
z#^(SM0Y`SmuK*+hj#*&*E<hsSQ?wXw03-rFO^b10AZp`S9}$2=n3Tb3NdY7RHgJWB
z4T*aAi%JIDRx<2EN(SpF88~WUnm8Mtnil5mxa&0B775pHy0K`pQv9Upm^HWlVPe&)
z7aUh#jOi_*)t!>1xlY>^xERV#g at i)A+N=pnvuic-uWXj-nJZ;lWuaB7uA?noU%S|F
zEqepeRk(Ca&lH7*i^a5ZIl6=j!d$Ct7ArY(#c4Flj>_e%oB6s0wc*xXD@*)dS at LJ4
zXy$FIIaand9MdbDi at v&&DeAhfp;c2~tle0RnpC-Mn at -zyYOYBkOV0C0!jX{osKZNN
z(la+H<5D_(EMZJ_nX_C=Tl|QQH?Nsyq1`rXbTL;eR;lRTGh0!9ThGtGBiF%s;7B?y
zJ)&<hkOSmXg+_b824 at iFDLjbye(|*9vkeU2A?7YcYmg??Fmj9MXcIHa-}|e|_<iCp
zDS40?Fec(V0sipi8E5_rVX}T at PpYJC#rYmo>a%#P|4f36<?~Of1Z`!A{5Vp7{r?h%
z{6U}pAz>h{-_!c_vp%Z-TPhysLw?*(+&A+DN<OUrFhC-{r#<atJ)`n}tn%~kBl6=u
z;=IhaRsN8#|ES8(^>co|{wdkXSU&%sR05t8<j1|u{*1>7Ln at v#5+x;7{xSoKD_Hsf
zx<!jIWg^-4!@wc7UwK%~SHAc``F|s$^&eb6BVUk!R#OZpzNh+cE1l1u{kebahn9O)
kV%y48vXuJ%6{G(Q9{Jn)kzjxAu;hlmR1RSH|K!jAACLKYRR910
literal 3448
zcmb_eO>7%Q6dv16V$viHAqP+qq^J at _qMLP$9D-1B<ZQdpG(`C!qN3Vt)@#SqKa0I~
z+#;)$A|WhODToV*100aZp$Ei;8w9lojyV*mNE|Bhqe$i89*}YXnfG?*+2gg%1)enf
zX1;mzzVFS>j(ts;KkN7T7 at 3cqVXYCNjFp3}e$?qk**HY5s at 31r?LTDoMx}9pxLQ^A
z?=!Wg>_e{(@LlyrvF=O(3_~}n8NPj6zI02iep`k33kOx@*H)%l<-iGUG<?C}$+PU)
z=Na)u)oNu=tsVl$56}f)tbc>LxrXoExqZ-4S8FKhK&=(sbf~TfGnG9zxCSY<Z%08z
ztpXxkCHJbz&tJC^)++a$U<O)-V2jw9zBgFxMXrYn0J1~1cA>6TgO_eOdn7!Jw4O~)
zl+1h~mCH^{g(X>%lPP=R)TV7)g%>6#VX#@;kc?brGMz5DkJDB at _oivs5=Mq*!trT6
zq8sK+Vp<MGOgU`K$VMa_nTjOh8`Ft+VrFK;ke at -;aZc^Ky2O0tQQz^Qf#43*^Elwx
z&>q9b?8xXl{@8H;3IxEA=6qKd=be=UA7j*UT7MD-*wEt8j$ns!_-7%>>`?!x8#9k{
zVAr6v$E`KvaEtq)4M0PF91n6o1b!IWzu5;cd4xS^bc+cve>a!~Ts3WT!%nE9vJJ;U
zz){!%1CEN@?G6^u1xGaCREE8lJptV at K_~7h+SAZr8#^os`JWQ>;NGIW4y{|f+5`Wt
z2mVnH9LwsK|4T;?zA at LFGX>pGpmmFX0P!dM_-0+B9XtfQTRgpgd^5=MSHrbad_Cev
z1w1U^$U^b(sXB)7n3M1|7j{mBh_4Iyh!B55z>f*|O9GB{Q2qr0e^|it0zM|-Zwt7{
z%VFpHpl=(o2|j_xm-Z5&^8)?|@1tAieT)~sj+B50cpu%n0^TR!?+ZA7zhr~sM~{t-
zFzw<(WJS*>O*<A+mhDieVCPfWq*h9qTQK>YZ5HejMx9 at _Bkr70^28}lKy!XBL_kO`
zW>aq!P0h0NFLN5jnU?ZqT9<6IY%{z_GiDY#$$YM8F<mk&3mCIo8F<Fii=_;cvN_w7
z&MmB-F4($pnMru at YI-~lmvoY8tJ$qoHm)t1g<{5JZf<i^OXPJNCJjR~%Z6#$nyqi7
z0f9Q82mVUN at l7$3b`fjK=$B2+l}@r>S at IT*yCv4QqA7FMt1GhB$@o8|#qEMr3m#(H
z*w~b^xD52?VzIV*LwrZ#x~)rdYp^{DNz;<$vSz`LTrR7pQ}z|DBzG*7>8$)0|0gUK
z&ne}4jUUD*#lsDgaJ{ryg=6B`#egV2z~~-!N1b<587A;9iBbUfpCSmh<2r`l9!jBa
z^HGlf0v<JaWU|lreCvjE0iKr6GWH(y at ILX{b)Jy!Qsl?`k=BzR1ajo>_XzlcC#2sM
zKJ2)g`(Uw?%d=kQmjvz)8uH^Fd+T52{C at 9x6a_~5-BC+FjeFI<!}Adz^5Z^H-Q;g_
zesBFz&QHH%#OKx1i~mE;Pwx-;u at Nu%`<y at EsehgGlYZj&j(>+ZCzogaF5iDTXUL6O
zXg%TEfFYF(O|(tUpAkXmbGYe07cepOM+y|dF0ntknB|er?(+4!p7o at k;5*R4`lAGJ
zzsKv};bW{H-yN-|`o97!FyF|5yAG{si~K^MdjZ#@dCU46Ft2uu+vOnspFu<S5Hv6U
EKZPRj`v3p{
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 9e4e3eca2117b..1fc4be08cd853 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -925,6 +925,7 @@ void lifetimebound_return_reference() {
struct LifetimeBoundCtor {
LifetimeBoundCtor();
LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]);
+ LifetimeBoundCtor(int* p [[clang::lifetimebound]]);
};
void lifetimebound_ctor() {
@@ -978,11 +979,32 @@ void lifetimebound_make_unique_temp() {
(void)ptr; // expected-note {{later used here}}
}
+void lifetimebound_make_unique_raw_ptr() {
+ std::unique_ptr<LifetimeBoundCtor> ptr;
+ int x = 0;
+ {
+ int* p = &x;
+ // FIXME: No warning expected with current implementation
+ ptr = std::make_unique<LifetimeBoundCtor>(p);
+ }
+ (void)ptr;
+}
+
+void lifetimebound_make_unique_string_view_local() {
+ std::unique_ptr<LifetimeBoundCtor> ptr;
+ {
+ std::string s;
+ std::string_view sv(s);
+ // FIXME: No warning expected with current implementation because of reference mismatch
+ ptr = std::make_unique<LifetimeBoundCtor>(sv);
+ }
+ (void)ptr;
+}
+
struct MultiLifetimeBoundCtor {
MultiLifetimeBoundCtor(const MyObj& obj1 [[clang::lifetimebound]], const MyObj& obj2);
MultiLifetimeBoundCtor(const MyObj& obj1, const MyObj& obj2 [[clang::lifetimebound]], int);
MultiLifetimeBoundCtor(const MyObj& obj1 [[clang::lifetimebound]], const MyObj& obj2 [[clang::lifetimebound]], double);
- MultiLifetimeBoundCtor(std::string_view sv [[clang::lifetimebound]]);
};
void lifetimebound_make_unique_multi_params() {
>From 76a97f3a78f39c51789f8a020ab407344a45ee9d Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sat, 11 Apr 2026 13:27:10 +0000
Subject: [PATCH 03/16] remove a.o
---
a.o | Bin 2984 -> 0 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 a.o
diff --git a/a.o b/a.o
deleted file mode 100644
index 6a53ddbada9cbc2494763f0d57e07746d0d02737..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2984
zcmbVO&2Jl35P!DYBrQoWg#)M at T*Ltm-Po<;IDE;Gv&~Yat(7LCs#GoO_1bacFYLAB
z7DYsgRLQa;aX~_GK?o!c95`^{0z$3S9DD2^08%74gcCVLGV^=;rgk<qhmQ1iW`1uz
z-_Ab!Gky6=Fc1(-0r7$8Ym5r9Kh~F1QcQ`L$#Tu;{Auj`9eJ!D0X25 at Bcr1q7`t2h
z#%}Xq-vhVyJz?ij<jzCs%@5_DGCEs(M(2=xpO8qrdGH(R at ccTDy}hSKmtuFL68%dU
z-6kPhd!A93Tz4L&?mQ&usnPkpLy at lScl1Ag?FZ_rN<^<0m=p;i5~o+iyYF!|!s|yB
zK*<h`?zID>GvTY6?Cp|ODMVUMy-}=IB9|^}Q7u|1x{<fmUANYFXJ&?!^=4MHtL2$e
zspUN`*6P)}j_qo&%qM5(^SPumH&2wEwG*>ZJDarT;<LHAcs`m<M(ucRKH<EL>RwSL
z2JWwjKsy{bKRG_}Ira5A;aH%{cq~kZ9|Y4=V-+$W6?@#?YlHi%{e8fJ`<Z1KdHidr
z=Q;kHq+o$IX`O<=If6GR$in1UnEVMoO$%c(P7C at O#a|#kN$dY;kv30>e|p1gLLxW}
z79pAO<W@*la2zk9pdmQWkgOC^pJ0A&Ag?@I!p_jf8v}W9CZMyl=on7W)e-pm2z*J#
z$H{pl-x-M+TEpT$7==@u3qhQ`N0<fBF5$!CMC7jbeqnpm^GFUK>3Hv`it!61gMg!V
z#^(SM0Y`SmuK*+hj#*&*E<hsSQ?wXw03-rFO^b10AZp`S9}$2=n3Tb3NdY7RHgJWB
z4T*aAi%JIDRx<2EN(SpF88~WUnm8Mtnil5mxa&0B775pHy0K`pQv9Upm^HWlVPe&)
z7aUh#jOi_*)t!>1xlY>^xERV#g at i)A+N=pnvuic-uWXj-nJZ;lWuaB7uA?noU%S|F
zEqepeRk(Ca&lH7*i^a5ZIl6=j!d$Ct7ArY(#c4Flj>_e%oB6s0wc*xXD@*)dS at LJ4
zXy$FIIaand9MdbDi at v&&DeAhfp;c2~tle0RnpC-Mn at -zyYOYBkOV0C0!jX{osKZNN
z(la+H<5D_(EMZJ_nX_C=Tl|QQH?Nsyq1`rXbTL;eR;lRTGh0!9ThGtGBiF%s;7B?y
zJ)&<hkOSmXg+_b824 at iFDLjbye(|*9vkeU2A?7YcYmg??Fmj9MXcIHa-}|e|_<iCp
zDS40?Fec(V0sipi8E5_rVX}T at PpYJC#rYmo>a%#P|4f36<?~Of1Z`!A{5Vp7{r?h%
z{6U}pAz>h{-_!c_vp%Z-TPhysLw?*(+&A+DN<OUrFhC-{r#<atJ)`n}tn%~kBl6=u
z;=IhaRsN8#|ES8(^>co|{wdkXSU&%sR05t8<j1|u{*1>7Ln at v#5+x;7{xSoKD_Hsf
zx<!jIWg^-4!@wc7UwK%~SHAc``F|s$^&eb6BVUk!R#OZpzNh+cE1l1u{kebahn9O)
kV%y48vXuJ%6{G(Q9{Jn)kzjxAu;hlmR1RSH|K!jAACLKYRR910
>From 2488a3695c99fb69220e14dc9b0e844f0d149a77 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sat, 11 Apr 2026 13:36:43 +0000
Subject: [PATCH 04/16] dangling field
---
.../Sema/warn-lifetime-safety-dangling-field.cpp | 16 ++++++++++++++++
clang/test/Sema/warn-lifetime-safety.cpp | 2 ++
2 files changed, 18 insertions(+)
diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
index 2afcd4a3dd97b..1321e804b739e 100644
--- a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
@@ -209,3 +209,19 @@ struct HasCallback {
};
} // namespace callable_wrappers
+
+namespace MakeUnique {
+struct MyObj {};
+
+struct LifetimeBoundCtor {
+ LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]);
+};
+
+struct HasUniquePtrField {
+ std::unique_ptr<LifetimeBoundCtor> field; // expected-note {{this field dangles}}
+
+ void setWithParam(MyObj obj) {
+ field = std::make_unique<LifetimeBoundCtor>(obj); // expected-warning {{address of stack memory escapes to a field}}
+ }
+};
+} // namespace MakeUnique
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 1fc4be08cd853..79ae7473cd316 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1001,6 +1001,8 @@ void lifetimebound_make_unique_string_view_local() {
(void)ptr;
}
+
+
struct MultiLifetimeBoundCtor {
MultiLifetimeBoundCtor(const MyObj& obj1 [[clang::lifetimebound]], const MyObj& obj2);
MultiLifetimeBoundCtor(const MyObj& obj1, const MyObj& obj2 [[clang::lifetimebound]], int);
>From 55a18bdc74b8a4cf5ca744b6974ba3b4fd327671 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sat, 11 Apr 2026 13:47:55 +0000
Subject: [PATCH 05/16] lifetime suggestion
---
.../Sema/warn-lifetime-safety-suggestions.cpp | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index d2cf1c175eb57..39162064226f2 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -547,3 +547,22 @@ void uaf_via_inferred_lifetimebound() {
}
} // namespace callable_wrappers
+namespace make_unique_suggestion {
+
+struct LifetimeBoundCtor {
+ LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]);
+};
+
+std::unique_ptr<LifetimeBoundCtor> create_target(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
+ return std::make_unique<LifetimeBoundCtor>(obj); // expected-note {{param returned here}}
+}
+
+void test_inference() {
+ std::unique_ptr<LifetimeBoundCtor> ptr;
+ {
+ MyObj obj;
+ ptr = create_target(obj); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
+}
+} // namespace make_unique_suggestion
>From 7381c4260d7a2c4b7c1974f338203b27d7348e9d Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sat, 11 Apr 2026 14:47:51 +0000
Subject: [PATCH 06/16] fix suggestions test
---
clang/test/Sema/warn-lifetime-safety-suggestions.cpp | 9 ++++++++-
clang/test/Sema/warn-lifetime-safety.cpp | 4 ----
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 39162064226f2..751ce34dcf54c 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -1,8 +1,14 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
+<<<<<<< HEAD
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -fixit %t/test_source.cpp
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%t -I%S -Werror=lifetime-safety-suggestions %t/test_source.cpp
+=======
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%S -I%t -verify %t/test_source.cpp
+// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%S -I%t -fixit %t/test_source.cpp
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%S -I%t -Werror=lifetime-safety-suggestions %t/test_source.cpp
+>>>>>>> 954c2bf91d18 (fix suggestions test)
View definition_before_header(View a);
@@ -10,6 +16,8 @@ View definition_before_header(View a);
#ifndef TEST_HEADER_H
#define TEST_HEADER_H
+#include "Inputs/lifetime-analysis.h"
+
struct View;
struct [[gsl::Owner]] MyObj {
@@ -67,7 +75,6 @@ struct ReturnThisPointer {
//--- test_source.cpp
#include "test_header.h"
-#include "Inputs/lifetime-analysis.h"
View definition_before_header(View a) {
return a; // expected-note {{param returned here}}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 79ae7473cd316..8a1ea47b90f51 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1001,8 +1001,6 @@ void lifetimebound_make_unique_string_view_local() {
(void)ptr;
}
-
-
struct MultiLifetimeBoundCtor {
MultiLifetimeBoundCtor(const MyObj& obj1 [[clang::lifetimebound]], const MyObj& obj2);
MultiLifetimeBoundCtor(const MyObj& obj1, const MyObj& obj2 [[clang::lifetimebound]], int);
@@ -2532,8 +2530,6 @@ std::string_view return_dangling_view_through_owner() {
return sv; // expected-note {{returned here}}
}
-// FIXME: False negative. Move assignment of unique_ptr is not defaulted,
-// so origins from `local` don't propagate to `ups`.
void owner_outlives_lifetimebound_source() {
std::unique_ptr<S> ups;
{
>From 68d9e5828f039781b53f78857004cbb7ba389392 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 16:34:18 +0000
Subject: [PATCH 07/16] extract ctor from body in end-of-tu
---
clang/lib/Sema/SemaAttr.cpp | 74 +++++++------------
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 ++
clang/test/Sema/Inputs/lifetime-analysis.h | 12 ++-
clang/test/Sema/warn-lifetime-safety.cpp | 57 +++++++-------
4 files changed, 68 insertions(+), 80 deletions(-)
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index d173b1ba58d8e..ef16cfcfbcdf6 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -221,7 +221,19 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}
+static const CXXNewExpr *findCXXNewExpr(const Stmt *S) {
+ if (!S) return nullptr;
+ if (const auto *E = dyn_cast<CXXNewExpr>(S))
+ return E;
+ for (const Stmt *Child : S->children())
+ if (Child)
+ if (const CXXNewExpr *E = findCXXNewExpr(Child))
+ return E;
+ return nullptr;
+}
+
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
+ llvm::errs() << "JETSKI: inferLifetimeBoundAttribute for " << FD->getNameAsString() << "\n";
if (FD->getNumParams() == 0)
return;
// Skip void returning functions (except constructors). This can occur in
@@ -252,56 +264,20 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
}
// Handle std::make_unique to propagate lifetimebound attributes from the
- // constructed type's constructor to make_unique's parameters.
- if (FD->isInStdNamespace() && FD->getDeclName().isIdentifier() &&
+ // constructed type's constructor to make_unique's parameters by looking
+ // into its body.
+ if (FD->getDeclName().isIdentifier() &&
FD->getName() == "make_unique") {
- if (!FD->isFunctionTemplateSpecialization())
- return;
-
- const TemplateArgumentList *TAL = FD->getTemplateSpecializationArgs();
- if (!TAL || TAL->size() < 1)
- return;
-
- // make_unique's first template argument is the type being constructed.
- TemplateArgument TA = TAL->get(0);
- if (TA.getKind() != TemplateArgument::Type)
- return;
-
- QualType T = TA.getAsType();
- const auto *RD = T->getAsCXXRecordDecl();
- if (!RD)
- return;
-
- // Find the constructor that matches make_unique's arguments.
- for (const auto *Ctor : RD->ctors()) {
- if (Ctor->getNumParams() != FD->getNumParams())
- continue;
-
- bool Compatible = true;
- for (unsigned i = 0; i < Ctor->getNumParams(); ++i) {
- QualType CtorParamType = Ctor->getParamDecl(i)->getType();
- QualType FDParamType = FD->getParamDecl(i)->getType();
- // Compare types ignoring references.
- if (!Context.hasSameUnqualifiedType(
- CtorParamType.getNonReferenceType(),
- FDParamType.getNonReferenceType())) {
- Compatible = false;
- break;
- }
- }
-
- if (!Compatible)
- continue;
- // Propagate lifetimebound attributes only if the constructor parameter is
- // a reference. This avoids incorrect loan tracking when a by-value view
- // (like string_view) is passed by reference to make_unique.
- for (unsigned i = 0; i < Ctor->getNumParams(); ++i)
- if (Ctor->getParamDecl(i)->hasAttr<LifetimeBoundAttr>() &&
- Ctor->getParamDecl(i)->getType()->isReferenceType())
- FD->getParamDecl(i)->addAttr(
- LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
- break; // Found matching constructor, done.
- }
+ const FunctionDecl *BodyDecl = nullptr;
+ if (FD->getBody(BodyDecl))
+ if (const CXXNewExpr *NewExpr = findCXXNewExpr(BodyDecl->getBody()))
+ if (const CXXConstructExpr *ConstructExpr = NewExpr->getConstructExpr())
+ if (const CXXConstructorDecl *Ctor = ConstructExpr->getConstructor())
+ for (unsigned i = 0; i < Ctor->getNumParams(); ++i)
+ if (Ctor->getParamDecl(i)->hasAttr<LifetimeBoundAttr>() &&
+ i < FD->getNumParams())
+ FD->getParamDecl(i)->addAttr(
+ LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
return;
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 954160d4112a5..6158f05bdba61 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5552,6 +5552,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Function->isInvalidDecl() || isa<CXXDeductionGuideDecl>(Function))
return;
+
+
// Never instantiate an explicit specialization except if it is a class scope
// explicit specialization.
TemplateSpecializationKind TSK =
@@ -5969,6 +5971,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// context seems wrong. Investigate more.
ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true);
+
+ inferLifetimeBoundAttribute(Function);
+
checkReferenceToTULocalFromOtherTU(Function, PointOfInstantiation);
if (PatternDecl->isDependentContext())
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h
index 3879f3e529bfc..24e61d536be8c 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -194,8 +194,9 @@ struct basic_string {
using string = basic_string<char>;
template<typename T>
-struct unique_ptr {
+struct [[gsl::Owner]] unique_ptr {
unique_ptr();
+ explicit unique_ptr(T*);
unique_ptr(unique_ptr<T>&&);
unique_ptr& operator=(unique_ptr<T>&&);
~unique_ptr();
@@ -205,8 +206,15 @@ struct unique_ptr {
T *get() const;
};
+#ifdef WITH_LIFETIME_SAFETY_BODY
template<typename T, typename... Args>
-unique_ptr<T> make_unique(Args&&... args);
+unique_ptr<T> make_unique(Args&&... args) {
+ return unique_ptr<T>(new T(args...));
+}
+#else
+template<typename T, typename... Args>
+unique_ptr<T> make_unique(Args&&... args [[clang::lifetimebound]]);
+#endif
template<typename T>
struct optional {
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 8a1ea47b90f51..e88dfd85ce152 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify=expected,function %s
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify=expected,tu %s
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -fcxx-exceptions -verify=expected,function %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -DWITH_LIFETIME_SAFETY_BODY -verify=expected,function %s
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -DWITH_LIFETIME_SAFETY_BODY -verify=expected,tu %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -fcxx-exceptions -DWITH_LIFETIME_SAFETY_BODY -verify=expected,function %s
#include "Inputs/lifetime-analysis.h"
@@ -926,6 +926,7 @@ struct LifetimeBoundCtor {
LifetimeBoundCtor();
LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]);
LifetimeBoundCtor(int* p [[clang::lifetimebound]]);
+ LifetimeBoundCtor(std::string_view sv [[clang::lifetimebound]]);
};
void lifetimebound_ctor() {
@@ -968,15 +969,15 @@ void lifetimebound_make_unique() {
std::unique_ptr<LifetimeBoundCtor> ptr;
{
MyObj obj;
- ptr = std::make_unique<LifetimeBoundCtor>(obj); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_temp() {
- std::unique_ptr<LifetimeBoundCtor> ptr = std::make_unique<LifetimeBoundCtor>(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
- // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ std::unique_ptr<LifetimeBoundCtor> ptr = std::make_unique<LifetimeBoundCtor>(MyObj()); // tu-warning {{object whose reference is captured does not live long enough}} \
+ // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_raw_ptr() {
@@ -984,10 +985,9 @@ void lifetimebound_make_unique_raw_ptr() {
int x = 0;
{
int* p = &x;
- // FIXME: No warning expected with current implementation
- ptr = std::make_unique<LifetimeBoundCtor>(p);
- }
- (void)ptr;
+ ptr = std::make_unique<LifetimeBoundCtor>(p); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_string_view_local() {
@@ -995,10 +995,9 @@ void lifetimebound_make_unique_string_view_local() {
{
std::string s;
std::string_view sv(s);
- // FIXME: No warning expected with current implementation because of reference mismatch
- ptr = std::make_unique<LifetimeBoundCtor>(sv);
- }
- (void)ptr;
+ ptr = std::make_unique<LifetimeBoundCtor>(sv); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
struct MultiLifetimeBoundCtor {
@@ -1012,9 +1011,9 @@ void lifetimebound_make_unique_multi_params() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_multi_params2() {
@@ -1022,9 +1021,9 @@ void lifetimebound_make_unique_multi_params2() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_multi_params3_1() {
@@ -1032,9 +1031,9 @@ void lifetimebound_make_unique_multi_params3_1() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_multi_params3_2() {
@@ -1042,9 +1041,9 @@ void lifetimebound_make_unique_multi_params3_2() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
View lifetimebound_return_of_local() {
>From d9c43ca929fa09b7183e34b6f31f89c927a16fa5 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 17:46:36 +0000
Subject: [PATCH 08/16] extract ctor from CXXNew
---
clang/lib/Sema/SemaAttr.cpp | 61 ++++++++++++++++--------
clang/test/Sema/warn-lifetime-safety.cpp | 48 +++++++++----------
2 files changed, 65 insertions(+), 44 deletions(-)
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index ef16cfcfbcdf6..b4d457c4d06b5 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Initialization.h"
#include <optional>
using namespace clang;
@@ -221,19 +222,8 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}
-static const CXXNewExpr *findCXXNewExpr(const Stmt *S) {
- if (!S) return nullptr;
- if (const auto *E = dyn_cast<CXXNewExpr>(S))
- return E;
- for (const Stmt *Child : S->children())
- if (Child)
- if (const CXXNewExpr *E = findCXXNewExpr(Child))
- return E;
- return nullptr;
-}
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
- llvm::errs() << "JETSKI: inferLifetimeBoundAttribute for " << FD->getNameAsString() << "\n";
if (FD->getNumParams() == 0)
return;
// Skip void returning functions (except constructors). This can occur in
@@ -264,20 +254,51 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
}
// Handle std::make_unique to propagate lifetimebound attributes from the
- // constructed type's constructor to make_unique's parameters by looking
- // into its body.
+ // constructed type's constructor to make_unique's parameters by performing
+ // constructor lookup.
if (FD->getDeclName().isIdentifier() &&
FD->getName() == "make_unique") {
- const FunctionDecl *BodyDecl = nullptr;
- if (FD->getBody(BodyDecl))
- if (const CXXNewExpr *NewExpr = findCXXNewExpr(BodyDecl->getBody()))
- if (const CXXConstructExpr *ConstructExpr = NewExpr->getConstructExpr())
- if (const CXXConstructorDecl *Ctor = ConstructExpr->getConstructor())
- for (unsigned i = 0; i < Ctor->getNumParams(); ++i)
+ QualType ReturnType = FD->getReturnType();
+ const auto *RT = ReturnType->getAs<RecordType>();
+ if (!RT) return;
+ const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ if (!Spec) return;
+ if (Spec->getTemplateArgs().size() == 0) return;
+ QualType T = Spec->getTemplateArgs()[0].getAsType();
+
+ SmallVector<Expr *, 4> Args;
+ for (auto *Parm : FD->parameters()) {
+ QualType ParmTy = Parm->getType();
+ ExprValueKind VK = VK_LValue;
+ QualType ArgTy = ParmTy;
+ if (const auto *RefTy = ParmTy->getAs<ReferenceType>()) {
+ ArgTy = RefTy->getPointeeType();
+ if (ParmTy->isRValueReferenceType())
+ VK = VK_XValue;
+ }
+ Args.push_back(new (Context) OpaqueValueExpr(FD->getLocation(), ArgTy, VK));
+ }
+
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
+ InitializationKind Kind = InitializationKind::CreateDirect(FD->getLocation(), FD->getLocation(), FD->getLocation());
+ InitializationSequence InitSeq(*this, Entity, Kind, Args);
+
+ if (InitSeq) {
+ for (const auto &Step : InitSeq.steps()) {
+ if (Step.Kind == InitializationSequence::SK_ConstructorInitialization) {
+ if (const auto *Ctor = dyn_cast_or_null<CXXConstructorDecl>(Step.Function.Function)) {
+ for (unsigned i = 0; i < Ctor->getNumParams(); ++i) {
if (Ctor->getParamDecl(i)->hasAttr<LifetimeBoundAttr>() &&
- i < FD->getNumParams())
+ i < FD->getNumParams()) {
FD->getParamDecl(i)->addAttr(
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
return;
}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index e88dfd85ce152..343129995cf9b 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -969,15 +969,15 @@ void lifetimebound_make_unique() {
std::unique_ptr<LifetimeBoundCtor> ptr;
{
MyObj obj;
- ptr = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(obj); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
void lifetimebound_make_unique_temp() {
- std::unique_ptr<LifetimeBoundCtor> ptr = std::make_unique<LifetimeBoundCtor>(MyObj()); // tu-warning {{object whose reference is captured does not live long enough}} \
- // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ std::unique_ptr<LifetimeBoundCtor> ptr = std::make_unique<LifetimeBoundCtor>(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
+ // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
void lifetimebound_make_unique_raw_ptr() {
@@ -985,9 +985,9 @@ void lifetimebound_make_unique_raw_ptr() {
int x = 0;
{
int* p = &x;
- ptr = std::make_unique<LifetimeBoundCtor>(p); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(p); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
void lifetimebound_make_unique_string_view_local() {
@@ -995,9 +995,9 @@ void lifetimebound_make_unique_string_view_local() {
{
std::string s;
std::string_view sv(s);
- ptr = std::make_unique<LifetimeBoundCtor>(sv); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(sv); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
struct MultiLifetimeBoundCtor {
@@ -1011,9 +1011,9 @@ void lifetimebound_make_unique_multi_params() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
void lifetimebound_make_unique_multi_params2() {
@@ -1021,9 +1021,9 @@ void lifetimebound_make_unique_multi_params2() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
void lifetimebound_make_unique_multi_params3_1() {
@@ -1031,9 +1031,9 @@ void lifetimebound_make_unique_multi_params3_1() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
void lifetimebound_make_unique_multi_params3_2() {
@@ -1041,9 +1041,9 @@ void lifetimebound_make_unique_multi_params3_2() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
+ } // expected-note {{destroyed here}}
+ (void)ptr; // expected-note {{later used here}}
}
View lifetimebound_return_of_local() {
>From 1622dd0e96a61ddfb4872d3bc81e6d0b9656405f Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 17:49:46 +0000
Subject: [PATCH 09/16] revertarificial lookup
---
clang/lib/Sema/SemaAttr.cpp | 61 ++++++++----------------
clang/test/Sema/warn-lifetime-safety.cpp | 48 +++++++++----------
2 files changed, 44 insertions(+), 65 deletions(-)
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index b4d457c4d06b5..ef16cfcfbcdf6 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -19,7 +19,6 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Initialization.h"
#include <optional>
using namespace clang;
@@ -222,8 +221,19 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}
+static const CXXNewExpr *findCXXNewExpr(const Stmt *S) {
+ if (!S) return nullptr;
+ if (const auto *E = dyn_cast<CXXNewExpr>(S))
+ return E;
+ for (const Stmt *Child : S->children())
+ if (Child)
+ if (const CXXNewExpr *E = findCXXNewExpr(Child))
+ return E;
+ return nullptr;
+}
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
+ llvm::errs() << "JETSKI: inferLifetimeBoundAttribute for " << FD->getNameAsString() << "\n";
if (FD->getNumParams() == 0)
return;
// Skip void returning functions (except constructors). This can occur in
@@ -254,51 +264,20 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
}
// Handle std::make_unique to propagate lifetimebound attributes from the
- // constructed type's constructor to make_unique's parameters by performing
- // constructor lookup.
+ // constructed type's constructor to make_unique's parameters by looking
+ // into its body.
if (FD->getDeclName().isIdentifier() &&
FD->getName() == "make_unique") {
- QualType ReturnType = FD->getReturnType();
- const auto *RT = ReturnType->getAs<RecordType>();
- if (!RT) return;
- const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
- if (!Spec) return;
- if (Spec->getTemplateArgs().size() == 0) return;
- QualType T = Spec->getTemplateArgs()[0].getAsType();
-
- SmallVector<Expr *, 4> Args;
- for (auto *Parm : FD->parameters()) {
- QualType ParmTy = Parm->getType();
- ExprValueKind VK = VK_LValue;
- QualType ArgTy = ParmTy;
- if (const auto *RefTy = ParmTy->getAs<ReferenceType>()) {
- ArgTy = RefTy->getPointeeType();
- if (ParmTy->isRValueReferenceType())
- VK = VK_XValue;
- }
- Args.push_back(new (Context) OpaqueValueExpr(FD->getLocation(), ArgTy, VK));
- }
-
- InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
- InitializationKind Kind = InitializationKind::CreateDirect(FD->getLocation(), FD->getLocation(), FD->getLocation());
- InitializationSequence InitSeq(*this, Entity, Kind, Args);
-
- if (InitSeq) {
- for (const auto &Step : InitSeq.steps()) {
- if (Step.Kind == InitializationSequence::SK_ConstructorInitialization) {
- if (const auto *Ctor = dyn_cast_or_null<CXXConstructorDecl>(Step.Function.Function)) {
- for (unsigned i = 0; i < Ctor->getNumParams(); ++i) {
+ const FunctionDecl *BodyDecl = nullptr;
+ if (FD->getBody(BodyDecl))
+ if (const CXXNewExpr *NewExpr = findCXXNewExpr(BodyDecl->getBody()))
+ if (const CXXConstructExpr *ConstructExpr = NewExpr->getConstructExpr())
+ if (const CXXConstructorDecl *Ctor = ConstructExpr->getConstructor())
+ for (unsigned i = 0; i < Ctor->getNumParams(); ++i)
if (Ctor->getParamDecl(i)->hasAttr<LifetimeBoundAttr>() &&
- i < FD->getNumParams()) {
+ i < FD->getNumParams())
FD->getParamDecl(i)->addAttr(
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
- }
- }
- }
- break;
- }
- }
- }
return;
}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 343129995cf9b..e88dfd85ce152 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -969,15 +969,15 @@ void lifetimebound_make_unique() {
std::unique_ptr<LifetimeBoundCtor> ptr;
{
MyObj obj;
- ptr = std::make_unique<LifetimeBoundCtor>(obj); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_temp() {
- std::unique_ptr<LifetimeBoundCtor> ptr = std::make_unique<LifetimeBoundCtor>(MyObj()); // expected-warning {{object whose reference is captured does not live long enough}} \
- // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ std::unique_ptr<LifetimeBoundCtor> ptr = std::make_unique<LifetimeBoundCtor>(MyObj()); // tu-warning {{object whose reference is captured does not live long enough}} \
+ // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_raw_ptr() {
@@ -985,9 +985,9 @@ void lifetimebound_make_unique_raw_ptr() {
int x = 0;
{
int* p = &x;
- ptr = std::make_unique<LifetimeBoundCtor>(p); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(p); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_string_view_local() {
@@ -995,9 +995,9 @@ void lifetimebound_make_unique_string_view_local() {
{
std::string s;
std::string_view sv(s);
- ptr = std::make_unique<LifetimeBoundCtor>(sv); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(sv); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
struct MultiLifetimeBoundCtor {
@@ -1011,9 +1011,9 @@ void lifetimebound_make_unique_multi_params() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_multi_params2() {
@@ -1021,9 +1021,9 @@ void lifetimebound_make_unique_multi_params2() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_multi_params3_1() {
@@ -1031,9 +1031,9 @@ void lifetimebound_make_unique_multi_params3_1() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1.0); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
void lifetimebound_make_unique_multi_params3_2() {
@@ -1041,9 +1041,9 @@ void lifetimebound_make_unique_multi_params3_2() {
MyObj obj_long;
{
MyObj obj_short;
- ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); // expected-warning {{object whose reference is captured does not live long enough}}
- } // expected-note {{destroyed here}}
- (void)ptr; // expected-note {{later used here}}
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_long, obj_short, 1.0); // tu-warning {{object whose reference is captured does not live long enough}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
View lifetimebound_return_of_local() {
>From b423a2f6121afa7298846a32eff95db523073d51 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 17:56:59 +0000
Subject: [PATCH 10/16] fix test
---
clang/lib/Sema/SemaAttr.cpp | 1 -
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 --
clang/test/Sema/Inputs/lifetime-analysis.h | 5 -----
clang/test/Sema/warn-lifetime-analysis-nocfg.cpp | 5 ++---
clang/test/Sema/warn-lifetime-safety-dangling-field.cpp | 5 +++--
5 files changed, 5 insertions(+), 13 deletions(-)
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index ef16cfcfbcdf6..c103bf0af02eb 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -233,7 +233,6 @@ static const CXXNewExpr *findCXXNewExpr(const Stmt *S) {
}
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
- llvm::errs() << "JETSKI: inferLifetimeBoundAttribute for " << FD->getNameAsString() << "\n";
if (FD->getNumParams() == 0)
return;
// Skip void returning functions (except constructors). This can occur in
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6158f05bdba61..a633f8af187ff 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5552,8 +5552,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Function->isInvalidDecl() || isa<CXXDeductionGuideDecl>(Function))
return;
-
-
// Never instantiate an explicit specialization except if it is a class scope
// explicit specialization.
TemplateSpecializationKind TSK =
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h
index 24e61d536be8c..ee6d72459bb95 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -206,15 +206,10 @@ struct [[gsl::Owner]] unique_ptr {
T *get() const;
};
-#ifdef WITH_LIFETIME_SAFETY_BODY
template<typename T, typename... Args>
unique_ptr<T> make_unique(Args&&... args) {
return unique_ptr<T>(new T(args...));
}
-#else
-template<typename T, typename... Args>
-unique_ptr<T> make_unique(Args&&... args [[clang::lifetimebound]]);
-#endif
template<typename T>
struct optional {
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index e07c90f248764..00d45caae3b09 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -Wdangling -Wdangling-field -Wreturn-stack-address -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify=cfg %s
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify=cfg %s
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify=cfg,tu %s
#include "Inputs/lifetime-analysis.h"
@@ -180,8 +180,7 @@ struct LifetimeBoundCtor {
};
auto lifetimebound_make_unique_single_param() {
- return std::make_unique<LifetimeBoundCtor>(MyIntOwner{}); // expected-warning {{returning address of local temporary object}} \
- // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
+ return std::make_unique<LifetimeBoundCtor>(MyIntOwner{}); // tu-warning {{address of stack memory is returned later}} tu-note {{returned here}}
}
diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
index 1321e804b739e..5a4de105f217d 100644
--- a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify=expected,tu %s
#include "Inputs/lifetime-analysis.h"
@@ -218,10 +219,10 @@ struct LifetimeBoundCtor {
};
struct HasUniquePtrField {
- std::unique_ptr<LifetimeBoundCtor> field; // expected-note {{this field dangles}}
+ std::unique_ptr<LifetimeBoundCtor> field; // tu-note {{this field dangles}}
void setWithParam(MyObj obj) {
- field = std::make_unique<LifetimeBoundCtor>(obj); // expected-warning {{address of stack memory escapes to a field}}
+ field = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{address of stack memory escapes to a field}}
}
};
} // namespace MakeUnique
>From 492f88e6eb2ba826ded74a212b27112fce175d75 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 18:06:47 +0000
Subject: [PATCH 11/16] fix some tests.
---
clang/test/Sema/warn-lifetime-safety-suggestions.cpp | 3 ++-
clang/test/Sema/warn-lifetime-safety.cpp | 6 +++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 751ce34dcf54c..6088920300041 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -557,7 +557,8 @@ void uaf_via_inferred_lifetimebound() {
namespace make_unique_suggestion {
struct LifetimeBoundCtor {
- LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]);
+ View v;
+ LifetimeBoundCtor(const MyObj& obj): v(obj) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
};
std::unique_ptr<LifetimeBoundCtor> create_target(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index e88dfd85ce152..d7be878ea26bc 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -DWITH_LIFETIME_SAFETY_BODY -verify=expected,function %s
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -DWITH_LIFETIME_SAFETY_BODY -verify=expected,tu %s
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -fcxx-exceptions -DWITH_LIFETIME_SAFETY_BODY -verify=expected,function %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify=expected,function %s
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify=expected,tu %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -fcxx-exceptions -verify=expected,function %s
#include "Inputs/lifetime-analysis.h"
>From 8d29e8b79425d7c4b5213c1a881ca35bf7f6906b Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 18:31:29 +0000
Subject: [PATCH 12/16] fx more tests
---
clang/test/Sema/warn-lifetime-safety-suggestions.cpp | 11 +++--------
clang/test/Sema/warn-lifetime-safety.cpp | 10 ++++++++++
2 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 6088920300041..8dea9e6ddb7dc 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -1,14 +1,8 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
-<<<<<<< HEAD
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
-// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -fixit %t/test_source.cpp
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%t -I%S -Werror=lifetime-safety-suggestions %t/test_source.cpp
-=======
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%S -I%t -verify %t/test_source.cpp
// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%S -I%t -fixit %t/test_source.cpp
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%S -I%t -Werror=lifetime-safety-suggestions %t/test_source.cpp
->>>>>>> 954c2bf91d18 (fix suggestions test)
View definition_before_header(View a);
@@ -554,11 +548,12 @@ void uaf_via_inferred_lifetimebound() {
}
} // namespace callable_wrappers
+
namespace make_unique_suggestion {
struct LifetimeBoundCtor {
- View v;
- LifetimeBoundCtor(const MyObj& obj): v(obj) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
+ View v; // expected-note {{escapes to this field}}
+ LifetimeBoundCtor(const MyObj& obj): v(obj) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
};
std::unique_ptr<LifetimeBoundCtor> create_target(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index d7be878ea26bc..21f01b6ebf9f6 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1026,6 +1026,16 @@ void lifetimebound_make_unique_multi_params2() {
(void)ptr; // tu-note {{later used here}}
}
+void lifetimebound_make_unique_multi_params2_no_error_case() {
+ std::unique_ptr<MultiLifetimeBoundCtor> ptr;
+ MyObj obj_long;
+ {
+ MyObj obj_short;
+ ptr = std::make_unique<MultiLifetimeBoundCtor>(obj_short, obj_long, 1);
+ }
+ (void)ptr;
+}
+
void lifetimebound_make_unique_multi_params3_1() {
std::unique_ptr<MultiLifetimeBoundCtor> ptr;
MyObj obj_long;
>From 1ad729cd3ce6182fd3748d276f451d12b9148bbd Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 18:42:53 +0000
Subject: [PATCH 13/16] add fixme.
---
clang/test/Sema/warn-lifetime-safety-suggestions.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 8dea9e6ddb7dc..f633636520b1a 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -552,8 +552,9 @@ void uaf_via_inferred_lifetimebound() {
namespace make_unique_suggestion {
struct LifetimeBoundCtor {
- View v; // expected-note {{escapes to this field}}
- LifetimeBoundCtor(const MyObj& obj): v(obj) {} // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
+ View v;
+ // FIXME: This test fails to propagate the lifetimebound in ctor if this is inferred (instead of the current explicit annotation).
+ LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]): v(obj) {}
};
std::unique_ptr<LifetimeBoundCtor> create_target(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
>From a0838a15d0b3fbb53b3a80a1cfd9b6ee30e6cae7 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 18:45:52 +0000
Subject: [PATCH 14/16] remove unintentional diff
---
clang/test/Sema/warn-lifetime-safety-suggestions.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index f633636520b1a..06ad78501ad7b 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -1,8 +1,8 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%S -I%t -verify %t/test_source.cpp
-// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%S -I%t -fixit %t/test_source.cpp
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%S -I%t -Werror=lifetime-safety-suggestions %t/test_source.cpp
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
+// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -fixit %t/test_source.cpp
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%t -I%S -Werror=lifetime-safety-suggestions %t/test_source.cpp
View definition_before_header(View a);
>From 646c43f7d46688492136faf7c02ad11443e378f8 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 18:52:57 +0000
Subject: [PATCH 15/16] format test. add negative test.
---
.../Sema/warn-lifetime-safety-suggestions.cpp | 3 +--
clang/test/Sema/warn-lifetime-safety.cpp | 19 +++++++++++++++----
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
index 06ad78501ad7b..ace6265864684 100644
--- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp
@@ -10,8 +10,6 @@ View definition_before_header(View a);
#ifndef TEST_HEADER_H
#define TEST_HEADER_H
-#include "Inputs/lifetime-analysis.h"
-
struct View;
struct [[gsl::Owner]] MyObj {
@@ -69,6 +67,7 @@ struct ReturnThisPointer {
//--- test_source.cpp
#include "test_header.h"
+#include "Inputs/lifetime-analysis.h"
View definition_before_header(View a) {
return a; // expected-note {{param returned here}}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 21f01b6ebf9f6..f4ccd320259ff 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -925,6 +925,7 @@ void lifetimebound_return_reference() {
struct LifetimeBoundCtor {
LifetimeBoundCtor();
LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]);
+ LifetimeBoundCtor(const MyObj& obj, int); // not lifetimebound ctor.
LifetimeBoundCtor(int* p [[clang::lifetimebound]]);
LifetimeBoundCtor(std::string_view sv [[clang::lifetimebound]]);
};
@@ -970,8 +971,18 @@ void lifetimebound_make_unique() {
{
MyObj obj;
ptr = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
+}
+
+void non_lifetimebound_make_unique() {
+ std::unique_ptr<LifetimeBoundCtor> ptr;
+ {
+ MyObj obj;
+ // No error as the ctor is not lifetimebound.
+ ptr = std::make_unique<LifetimeBoundCtor>(obj, 0);
+ }
+ (void)ptr;
}
void lifetimebound_make_unique_temp() {
@@ -996,8 +1007,8 @@ void lifetimebound_make_unique_string_view_local() {
std::string s;
std::string_view sv(s);
ptr = std::make_unique<LifetimeBoundCtor>(sv); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ } // tu-note {{destroyed here}}
+ (void)ptr; // tu-note {{later used here}}
}
struct MultiLifetimeBoundCtor {
>From 887e5a0f0ca7030e3651ed4f5323b881a4126dfb Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 15 Apr 2026 19:05:29 +0000
Subject: [PATCH 16/16] infer only for reference types
---
clang/lib/Sema/SemaAttr.cpp | 9 +++++----
clang/test/Sema/warn-lifetime-safety.cpp | 14 ++++++++------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index c103bf0af02eb..067b259ec8ea2 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -272,10 +272,11 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
if (const CXXNewExpr *NewExpr = findCXXNewExpr(BodyDecl->getBody()))
if (const CXXConstructExpr *ConstructExpr = NewExpr->getConstructExpr())
if (const CXXConstructorDecl *Ctor = ConstructExpr->getConstructor())
- for (unsigned i = 0; i < Ctor->getNumParams(); ++i)
- if (Ctor->getParamDecl(i)->hasAttr<LifetimeBoundAttr>() &&
- i < FD->getNumParams())
- FD->getParamDecl(i)->addAttr(
+ for (unsigned I = 0; I < Ctor->getNumParams(); ++I)
+ if (I < FD->getNumParams() &&
+ Ctor->getParamDecl(I)->hasAttr<LifetimeBoundAttr>() &&
+ Ctor->getParamDecl(I)->getType()->isReferenceType())
+ FD->getParamDecl(I)->addAttr(
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
return;
}
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index f4ccd320259ff..fba5523931b44 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -991,24 +991,26 @@ void lifetimebound_make_unique_temp() {
(void)ptr; // tu-note {{later used here}}
}
+// FIXME: make_unique annotation cannot be inferred for pointer param in constructor
void lifetimebound_make_unique_raw_ptr() {
std::unique_ptr<LifetimeBoundCtor> ptr;
int x = 0;
{
int* p = &x;
- ptr = std::make_unique<LifetimeBoundCtor>(p); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(p);
+ }
+ (void)ptr;
}
+// FIXME: make_unique annotation cannot be inferred for view-type param in constructor
void lifetimebound_make_unique_string_view_local() {
std::unique_ptr<LifetimeBoundCtor> ptr;
{
std::string s;
std::string_view sv(s);
- ptr = std::make_unique<LifetimeBoundCtor>(sv); // tu-warning {{object whose reference is captured does not live long enough}}
- } // tu-note {{destroyed here}}
- (void)ptr; // tu-note {{later used here}}
+ ptr = std::make_unique<LifetimeBoundCtor>(sv);
+ }
+ (void)ptr;
}
struct MultiLifetimeBoundCtor {
More information about the cfe-commits
mailing list