https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/191632
>From ea1e700d3c41ca48563e27c1a57fd7a86be50d8d Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 11 Apr 2026 13:11:00 +0000 Subject: [PATCH 01/11] 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 | 70 +++++++++++++++++- 8 files changed, 141 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@_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@3cqVXYCNjFp3}e$?qk**HY5s@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@_oivs5=Mq*!trT6 zq8sK+Vp<MGOgU`K$VMa_nTjOh8`Ft+VrFK;ke@-;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@K_~7h+SAZr8#^os`JWQ>;NGIW4y{|f+5`Wt z2mVnH9LwsK|4T;?zA@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@_Bkr70^28}lKy!XBL_kO` zW>aq!P0h0NFLN5jnU?ZqT9<6IY%{z_GiDY#$$YM8F<mk&3mCIo8F<Fii=_;cvN_w7 z&MmB-F4($pnMru@YI-~lmvoY8tJ$qoHm)t1g<{5JZf<i^OXPJNCJjR~%Z6#$nyqi7 z0f9Q82mVUN@l7$3b`fjK=$B2+l}@r>S@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@ILX{b)Jy!Qsl?`k=BzR1ajo>_XzlcC#2sM zKJ2)g`(Uw?%d=kQmjvz)8uH^Fd+T52{C@9x6a_~5-BC+FjeFI<!}Adz^5Z^H-Q;g_ zesBFz&QHH%#OKx1i~mE;Pwx-;u@Nu%`<y@EsehgGlYZj&j(>+ZCzogaF5iDTXUL6O zXg%TEfFYF(O|(tUpAkXmbGYe07cepOM+y|dF0ntknB|er?(+4!p7o@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 2a2ef88987286..be9dd03dfe3da 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -489,7 +489,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 fdd2671dee2e0..72c61042afb3a 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 d1e847d20cc50..67e6c0f18de5c 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 2aca44daeb0aa..29f4880993b42 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -936,6 +936,70 @@ void lifetimebound_ctor() { (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}} @@ -2425,9 +2489,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 93a273357ae251dddcdbe2f17e0c24159c922dc3 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 11 Apr 2026 13:26:11 +0000 Subject: [PATCH 02/11] 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@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@Bcr1q7`t2h z#%}Xq-vhVyJz?ij<jzCs%@5_DGCEs(M(2=xpO8qrdGH(R@ccTDy}hSKmtuFL68%dU z-6kPhd!A93Tz4L&?mQ&usnPkpLy@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@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@i)A+N=pnvuic-uWXj-nJZ;lWuaB7uA?noU%S|F zEqepeRk(Ca&lH7*i^a5ZIl6=j!d$Ct7ArY(#c4Flj>_e%oB6s0wc*xXD@*)dS@LJ4 zXy$FIIaand9MdbDi@v&&DeAhfp;c2~tle0RnpC-Mn@-zyYOYBkOV0C0!jX{osKZNN z(la+H<5D_(EMZJ_nX_C=Tl|QQH?Nsyq1`rXbTL;eR;lRTGh0!9ThGtGBiF%s;7B?y zJ)&<hkOSmXg+_b824@iFDLjbye(|*9vkeU2A?7YcYmg??Fmj9MXcIHa-}|e|_<iCp zDS40?Fec(V0sipi8E5_rVX}T@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@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@_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@3cqVXYCNjFp3}e$?qk**HY5s@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@_oivs5=Mq*!trT6 zq8sK+Vp<MGOgU`K$VMa_nTjOh8`Ft+VrFK;ke@-;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@K_~7h+SAZr8#^os`JWQ>;NGIW4y{|f+5`Wt z2mVnH9LwsK|4T;?zA@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@_Bkr70^28}lKy!XBL_kO` zW>aq!P0h0NFLN5jnU?ZqT9<6IY%{z_GiDY#$$YM8F<mk&3mCIo8F<Fii=_;cvN_w7 z&MmB-F4($pnMru@YI-~lmvoY8tJ$qoHm)t1g<{5JZf<i^OXPJNCJjR~%Z6#$nyqi7 z0f9Q82mVUN@l7$3b`fjK=$B2+l}@r>S@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@ILX{b)Jy!Qsl?`k=BzR1ajo>_XzlcC#2sM zKJ2)g`(Uw?%d=kQmjvz)8uH^Fd+T52{C@9x6a_~5-BC+FjeFI<!}Adz^5Z^H-Q;g_ zesBFz&QHH%#OKx1i~mE;Pwx-;u@Nu%`<y@EsehgGlYZj&j(>+ZCzogaF5iDTXUL6O zXg%TEfFYF(O|(tUpAkXmbGYe07cepOM+y|dF0ntknB|er?(+4!p7o@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 29f4880993b42..678354341a1fb 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() { @@ -951,11 +952,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 0913da75f7b756295eb3ba2ae2b9b82cc4d8518b Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 11 Apr 2026 13:27:10 +0000 Subject: [PATCH 03/11] 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@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@Bcr1q7`t2h z#%}Xq-vhVyJz?ij<jzCs%@5_DGCEs(M(2=xpO8qrdGH(R@ccTDy}hSKmtuFL68%dU z-6kPhd!A93Tz4L&?mQ&usnPkpLy@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@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@i)A+N=pnvuic-uWXj-nJZ;lWuaB7uA?noU%S|F zEqepeRk(Ca&lH7*i^a5ZIl6=j!d$Ct7ArY(#c4Flj>_e%oB6s0wc*xXD@*)dS@LJ4 zXy$FIIaand9MdbDi@v&&DeAhfp;c2~tle0RnpC-Mn@-zyYOYBkOV0C0!jX{osKZNN z(la+H<5D_(EMZJ_nX_C=Tl|QQH?Nsyq1`rXbTL;eR;lRTGh0!9ThGtGBiF%s;7B?y zJ)&<hkOSmXg+_b824@iFDLjbye(|*9vkeU2A?7YcYmg??Fmj9MXcIHa-}|e|_<iCp zDS40?Fec(V0sipi8E5_rVX}T@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@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 5606ec85aa480ae247b18bc293fd55a43ccff1fb Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 11 Apr 2026 13:36:43 +0000 Subject: [PATCH 04/11] dangling field --- .../warn-lifetime-safety-dangling-field.cpp | 18 ++++++++++++++++++ clang/test/Sema/warn-lifetime-safety.cpp | 2 ++ 2 files changed, 20 insertions(+) diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp index 79b0183ed91ec..604adfa0c8538 100644 --- a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp +++ b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp @@ -185,6 +185,7 @@ struct IndirectEscape2 { } }; +<<<<<<< HEAD namespace DanglingPointerFieldInBaseClass { struct BaseWithPointer { std::string_view view; // expected-note {{this field dangles}} @@ -196,3 +197,20 @@ struct DerivedWithCtor : BaseWithPointer { } }; } // namespace DanglingPointerFieldInBaseClass +======= +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 +>>>>>>> 6f5985bd6945 (dangling field) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 678354341a1fb..31e62cc9f72a5 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -974,6 +974,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 0f33a12d7e2249f7b57b0d946f76c7d2611107cf Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 11 Apr 2026 13:47:55 +0000 Subject: [PATCH 05/11] lifetime suggestion --- .../Sema/warn-lifetime-safety-suggestions.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp index b3b13038dc344..8db96103b683d 100644 --- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp +++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp @@ -67,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}} @@ -529,3 +530,23 @@ CaptureRefToBaseView test_ref_to_base_view() { return x; // expected-note {{returned here}} } } // namespace capturing_constructor + +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 954c2bf91d182b2f3aa4f2ac28e7d9ee5221d6ad Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 11 Apr 2026 14:47:51 +0000 Subject: [PATCH 06/11] fix suggestions test --- clang/test/Sema/warn-lifetime-safety-suggestions.cpp | 9 +++++---- clang/test/Sema/warn-lifetime-safety.cpp | 4 ---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp index 8db96103b683d..6688d80c8331b 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%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%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%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%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 View definition_before_header(View a); @@ -10,6 +10,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 +69,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 31e62cc9f72a5..3d18c48be8d29 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -974,8 +974,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); @@ -2507,8 +2505,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 8a697df3abc31e9e5e1979b9f9b056567665a8d6 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Wed, 15 Apr 2026 16:11:01 +0000 Subject: [PATCH 07/11] rebase --- clang/test/Sema/warn-lifetime-safety-dangling-field.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp index 604adfa0c8538..4ed4f535c2ae1 100644 --- a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp +++ b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp @@ -185,7 +185,7 @@ struct IndirectEscape2 { } }; -<<<<<<< HEAD + namespace DanglingPointerFieldInBaseClass { struct BaseWithPointer { std::string_view view; // expected-note {{this field dangles}} @@ -197,7 +197,7 @@ struct DerivedWithCtor : BaseWithPointer { } }; } // namespace DanglingPointerFieldInBaseClass -======= + namespace MakeUnique { struct MyObj {}; @@ -213,4 +213,4 @@ struct HasUniquePtrField { } }; } // namespace MakeUnique ->>>>>>> 6f5985bd6945 (dangling field) + >From bf480da67d50d06997774df7f4e743634e0e6833 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Wed, 15 Apr 2026 16:34:18 +0000 Subject: [PATCH 08/11] 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 67e6c0f18de5c..788a4ba104af3 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 3d18c48be8d29..b1ad35cbc8da2 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() { @@ -941,15 +942,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() { @@ -957,10 +958,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() { @@ -968,10 +968,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 { @@ -985,9 +984,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() { @@ -995,9 +994,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() { @@ -1005,9 +1004,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() { @@ -1015,9 +1014,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}} } >From 63f48f4baabe001a6508e6376e26a9a7bf99f38c Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Wed, 15 Apr 2026 17:46:36 +0000 Subject: [PATCH 09/11] 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 b1ad35cbc8da2..ba2747e07f4dd 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -942,15 +942,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() { @@ -958,9 +958,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() { @@ -968,9 +968,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 { @@ -984,9 +984,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() { @@ -994,9 +994,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() { @@ -1004,9 +1004,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() { @@ -1014,9 +1014,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}} } >From a60dc136a8ad5a8f5c00d584e578987d193a26be Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Wed, 15 Apr 2026 17:49:46 +0000 Subject: [PATCH 10/11] 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 ba2747e07f4dd..b1ad35cbc8da2 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -942,15 +942,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() { @@ -958,9 +958,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() { @@ -968,9 +968,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 { @@ -984,9 +984,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() { @@ -994,9 +994,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() { @@ -1004,9 +1004,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() { @@ -1014,9 +1014,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}} } >From 22b6a6bf36bafdb64b714d353b3f2c59b28ac5c3 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Wed, 15 Apr 2026 17:56:59 +0000 Subject: [PATCH 11/11] 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 788a4ba104af3..869a63b483c0a 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 4ed4f535c2ae1..e51d7308feb9f 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" @@ -206,10 +207,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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
