Skip to content

Commit 45ac84d

Browse files
SC llvm teamSC llvm team
SC llvm team
authored and
SC llvm team
committed
Merged main:902b2a26ab9e1e78dfb66b52fba4512c91472e09 into amd-gfx:9b007be77fcd
Local branch amd-gfx 9b007be Merged main:175aa864f33786f3a6a4ee7381cbcafd0758501a into amd-gfx:ad92d65754df Remote branch main 902b2a2 [clang] Add lifetimebound attr to std::span/std::string_view constructor (llvm#103716)
2 parents 9b007be + 902b2a2 commit 45ac84d

File tree

12 files changed

+119
-42
lines changed

12 files changed

+119
-42
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ Attribute Changes in Clang
220220
- ``[[clang::lifetimebound]]`` is now explicitly disallowed on explicit object member functions
221221
where they were previously silently ignored.
222222

223+
- Clang now automatically adds ``[[clang::lifetimebound]]`` to the parameters of
224+
``std::span, std::string_view`` constructors, this enables Clang to capture
225+
more cases where the returned reference outlives the object.
226+
(#GH100567)
227+
223228
Improvements to Clang's diagnostics
224229
-----------------------------------
225230

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,9 @@ class Sema final : public SemaBase {
18061806
/// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types.
18071807
void inferGslOwnerPointerAttribute(CXXRecordDecl *Record);
18081808

1809+
/// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
1810+
void inferLifetimeBoundAttribute(FunctionDecl *FD);
1811+
18091812
/// Add [[gsl::Pointer]] attributes for std:: types.
18101813
void inferGslPointerAttribute(TypedefNameDecl *TD);
18111814

clang/lib/Sema/SemaAttr.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,59 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
216216
inferGslPointerAttribute(Record, Record);
217217
}
218218

219+
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
220+
if (FD->getNumParams() == 0)
221+
return;
222+
223+
if (unsigned BuiltinID = FD->getBuiltinID()) {
224+
// Add lifetime attribute to std::move, std::fowrard et al.
225+
switch (BuiltinID) {
226+
case Builtin::BIaddressof:
227+
case Builtin::BI__addressof:
228+
case Builtin::BI__builtin_addressof:
229+
case Builtin::BIas_const:
230+
case Builtin::BIforward:
231+
case Builtin::BIforward_like:
232+
case Builtin::BImove:
233+
case Builtin::BImove_if_noexcept:
234+
if (ParmVarDecl *P = FD->getParamDecl(0u);
235+
!P->hasAttr<LifetimeBoundAttr>())
236+
P->addAttr(
237+
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
238+
break;
239+
default:
240+
break;
241+
}
242+
return;
243+
}
244+
if (auto *CMD = dyn_cast<CXXMethodDecl>(FD)) {
245+
const auto *CRD = CMD->getParent();
246+
if (!CRD->isInStdNamespace() || !CRD->getIdentifier())
247+
return;
248+
249+
if (isa<CXXConstructorDecl>(CMD)) {
250+
auto *Param = CMD->getParamDecl(0);
251+
if (Param->hasAttr<LifetimeBoundAttr>())
252+
return;
253+
if (CRD->getName() == "basic_string_view" &&
254+
Param->getType()->isPointerType()) {
255+
// construct from a char array pointed by a pointer.
256+
// basic_string_view(const CharT* s);
257+
// basic_string_view(const CharT* s, size_type count);
258+
Param->addAttr(
259+
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
260+
} else if (CRD->getName() == "span") {
261+
// construct from a reference of array.
262+
// span(std::type_identity_t<element_type> (&arr)[N]);
263+
const auto *LRT = Param->getType()->getAs<LValueReferenceType>();
264+
if (LRT && LRT->getPointeeType().IgnoreParens()->isArrayType())
265+
Param->addAttr(
266+
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
267+
}
268+
}
269+
}
270+
}
271+
219272
void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
220273
static const llvm::StringSet<> Nullable{
221274
"auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16608,27 +16608,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
1660816608
default:
1660916609
break;
1661016610
}
16611-
16612-
// Add lifetime attribute to std::move, std::fowrard et al.
16613-
switch (BuiltinID) {
16614-
case Builtin::BIaddressof:
16615-
case Builtin::BI__addressof:
16616-
case Builtin::BI__builtin_addressof:
16617-
case Builtin::BIas_const:
16618-
case Builtin::BIforward:
16619-
case Builtin::BIforward_like:
16620-
case Builtin::BImove:
16621-
case Builtin::BImove_if_noexcept:
16622-
if (ParmVarDecl *P = FD->getParamDecl(0u);
16623-
!P->hasAttr<LifetimeBoundAttr>())
16624-
P->addAttr(
16625-
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
16626-
break;
16627-
default:
16628-
break;
16629-
}
1663016611
}
1663116612

16613+
inferLifetimeBoundAttribute(FD);
1663216614
AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
1663316615

1663416616
// If C++ exceptions are enabled but we are told extern "C" functions cannot

clang/test/SemaCXX/attr-lifetimebound.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ template <class T> T *addressof(T &arg) {
238238
&const_cast<char &>(reinterpret_cast<const volatile char &>(arg)));
239239
}
240240

241+
template<typename T>
242+
struct basic_string_view {
243+
basic_string_view(const T *);
244+
};
245+
246+
template <class T> struct span {
247+
template<size_t _ArrayExtent>
248+
span(const T (&__arr)[_ArrayExtent]) noexcept;
249+
};
250+
241251
} // namespace foo
242252
} // namespace std
243253

@@ -266,3 +276,14 @@ namespace move_forward_et_al_examples {
266276
S *AddressOfOk = std::addressof(X);
267277
} // namespace move_forward_et_al_examples
268278

279+
namespace ctor_cases {
280+
std::basic_string_view<char> test1() {
281+
char abc[10];
282+
return abc; // expected-warning {{address of stack memory associated with local variable}}
283+
}
284+
285+
std::span<int> test2() {
286+
int abc[10];
287+
return abc; // expected-warning {{address of stack memory associated with local variable}}
288+
}
289+
} // namespace ctor_cases

libcxx/include/__math/traits.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,21 @@ _LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI boo
127127

128128
// isnormal
129129

130-
template <class _A1, __enable_if_t<is_floating_point<_A1>::value, int> = 0>
130+
template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
131131
_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(_A1 __x) _NOEXCEPT {
132+
return __x != 0;
133+
}
134+
135+
_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(float __x) _NOEXCEPT {
132136
return __builtin_isnormal(__x);
133137
}
134138

135-
template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0>
136-
_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(_A1 __x) _NOEXCEPT {
137-
return __x != 0;
139+
_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(double __x) _NOEXCEPT {
140+
return __builtin_isnormal(__x);
141+
}
142+
143+
_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(long double __x) _NOEXCEPT {
144+
return __builtin_isnormal(__x);
138145
}
139146

140147
// isgreater

libcxx/test/std/numerics/c.math/isnormal.pass.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,23 @@ struct TestInt {
6262
}
6363
};
6464

65+
template <typename T>
66+
struct ConvertibleTo {
67+
operator T() const { return T(1); }
68+
};
69+
6570
int main(int, char**) {
6671
types::for_each(types::floating_point_types(), TestFloat());
6772
types::for_each(types::integral_types(), TestInt());
6873

74+
// Make sure we can call `std::isnormal` with convertible types. This checks
75+
// whether overloads for all cv-unqualified floating-point types are working
76+
// as expected.
77+
{
78+
assert(std::isnormal(ConvertibleTo<float>()));
79+
assert(std::isnormal(ConvertibleTo<double>()));
80+
assert(std::isnormal(ConvertibleTo<long double>()));
81+
}
82+
6983
return 0;
7084
}

llvm/include/llvm/Config/llvm-config.h.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
/* Indicate that this is LLVM compiled from the amd-gfx branch. */
1818
#define LLVM_HAVE_BRANCH_AMD_GFX
19-
#define LLVM_MAIN_REVISION 509868
19+
#define LLVM_MAIN_REVISION 509872
2020

2121
/* Define if LLVM_ENABLE_DUMP is enabled */
2222
#cmakedefine LLVM_ENABLE_DUMP

llvm/lib/FileCheck/FileCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
298298
++I;
299299

300300
if (I == Str.size())
301-
return ErrorDiagnostic::get(SM, Str.slice(I, StringRef::npos),
301+
return ErrorDiagnostic::get(SM, Str.substr(I),
302302
StringRef("empty ") +
303303
(IsPseudo ? "pseudo " : "global ") +
304304
"variable name");

llvm/lib/Target/AMDGPU/R600InstrInfo.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,9 @@ void R600InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
7575
/// \returns true if \p MBBI can be moved into a new basic.
7676
bool R600InstrInfo::isLegalToSplitMBBAt(MachineBasicBlock &MBB,
7777
MachineBasicBlock::iterator MBBI) const {
78-
for (MachineInstr::const_mop_iterator I = MBBI->operands_begin(),
79-
E = MBBI->operands_end(); I != E; ++I) {
80-
if (I->isReg() && !I->getReg().isVirtual() && I->isUse() &&
81-
RI.isPhysRegLiveAcrossClauses(I->getReg()))
78+
for (const MachineOperand &MO : MBBI->all_uses())
79+
if (!MO.getReg().isVirtual() && RI.isPhysRegLiveAcrossClauses(MO.getReg()))
8280
return false;
83-
}
8481
return true;
8582
}
8683

@@ -219,15 +216,10 @@ bool R600InstrInfo::readsLDSSrcReg(const MachineInstr &MI) const {
219216
if (!isALUInstr(MI.getOpcode())) {
220217
return false;
221218
}
222-
for (MachineInstr::const_mop_iterator I = MI.operands_begin(),
223-
E = MI.operands_end();
224-
I != E; ++I) {
225-
if (!I->isReg() || !I->isUse() || I->getReg().isVirtual())
226-
continue;
227-
228-
if (R600::R600_LDS_SRC_REGRegClass.contains(I->getReg()))
219+
for (const MachineOperand &MO : MI.all_uses())
220+
if (MO.getReg().isPhysical() &&
221+
R600::R600_LDS_SRC_REGRegClass.contains(MO.getReg()))
229222
return true;
230-
}
231223
return false;
232224
}
233225

llvm/tools/llvm-objcopy/ObjcopyOptions.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -556,9 +556,9 @@ static Expected<int64_t> parseChangeSectionLMA(StringRef ArgValue,
556556
StringRef OptionName) {
557557
StringRef StringValue;
558558
if (ArgValue.starts_with("*+")) {
559-
StringValue = ArgValue.slice(2, StringRef::npos);
559+
StringValue = ArgValue.substr(2);
560560
} else if (ArgValue.starts_with("*-")) {
561-
StringValue = ArgValue.slice(1, StringRef::npos);
561+
StringValue = ArgValue.substr(1);
562562
} else if (ArgValue.contains("=")) {
563563
return createStringError(errc::invalid_argument,
564564
"bad format for " + OptionName +
@@ -608,7 +608,7 @@ parseChangeSectionAddr(StringRef ArgValue, StringRef OptionName,
608608
SectionPattern, SectionMatchStyle, ErrorCallback)))
609609
return std::move(E);
610610

611-
StringRef Value = ArgValue.slice(LastSymbolIndex + 1, StringRef::npos);
611+
StringRef Value = ArgValue.substr(LastSymbolIndex + 1);
612612
if (Value.empty()) {
613613
switch (UpdateSymbol) {
614614
case '+':

llvm/unittests/Support/VirtualFileSystemTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1583,7 +1583,7 @@ class VFSFromYAMLTest : public ::testing::Test {
15831583
IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem(),
15841584
StringRef YAMLFilePath = "") {
15851585
std::string VersionPlusContent("{\n 'version':0,\n");
1586-
VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1586+
VersionPlusContent += Content.substr(Content.find('{') + 1);
15871587
return getFromYAMLRawString(VersionPlusContent, ExternalFS, YAMLFilePath);
15881588
}
15891589

0 commit comments

Comments
 (0)