Skip to content

Commit b56631a

Browse files
committed
address comments
1 parent c1ac443 commit b56631a

File tree

8 files changed

+72
-64
lines changed

8 files changed

+72
-64
lines changed

a-84635e71.o.tmp

Whitespace-only changes.

a-9a215dcd.o.tmp

Whitespace-only changes.

a-d85fccc7.o.tmp

Whitespace-only changes.

a-f0f01220.o.tmp

Whitespace-only changes.

clang/include/clang/Basic/AttrDocs.td

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3922,8 +3922,8 @@ def LifetimeCaptureByDocs : Documentation {
39223922
let Category = DocCatFunction;
39233923
let Content = [{
39243924
Similar to `lifetimebound`_, the ``lifetime_capture_by(X)`` attribute on a function
3925-
parameter or implicit object parameter indicates that that objects that are referred to
3926-
by that parameter may also be referred to by the capturing entity ``X``.
3925+
parameter or implicit object parameter indicates that objects that are referred to by
3926+
that parameter may also be referred to by the capturing entity ``X``.
39273927

39283928
By default:
39293929

@@ -3932,7 +3932,7 @@ By default:
39323932
- A ``std::initializer_list<T>`` is considered to refer to its underlying array.
39333933
- Aggregates (arrays and simple ``struct``\s) are considered to refer to all
39343934
objects that their transitive subobjects refer to.
3935-
- View types (types annotated with [[``gsl::Pointer()``]]) are considered to refer
3935+
- View types (types annotated with ``[[gsl::Pointer()]]``) are considered to refer
39363936
to its pointee. This holds true even if the view type appears as a reference.
39373937
For example, both ``std::string_view`` and ``const std::string_view &`` are
39383938
considered to refer to a ``std::string``.
@@ -3990,7 +3990,7 @@ The attribute supports specifying more than one capturing entities:
39903990
s2.insert(a);
39913991
}
39923992

3993-
Currently clang would diagnose when a temporary is used as an argument to a
3993+
Currently Clang would diagnose when a temporary is used as an argument to a
39943994
parameter whose reference is captured.
39953995

39963996
.. code-block:: c++

clang/lib/Sema/CheckExprLifetime.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
254254
LocalVisitor Visit);
255255

256256
template <typename T> static bool isRecordWithAttr(QualType Type) {
257-
if (auto *RD = Type.getNonReferenceType()->getAsCXXRecordDecl())
257+
if (auto *RD = Type->getAsCXXRecordDecl())
258258
return RD->hasAttr<T>();
259259
return false;
260260
}
@@ -1437,6 +1437,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
14371437
// warnings or errors on inner temporaries within this one's initializer.
14381438
return false;
14391439
};
1440+
14401441
bool HasReferenceBinding = Init->isGLValue();
14411442
llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
14421443
switch (LK) {

clang/lib/Sema/SemaChecking.cpp

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3233,46 +3233,41 @@ void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
32333233
void Sema::checkLifetimeCaptureBy(FunctionDecl *FD, bool IsMemberFunction,
32343234
const Expr *ThisArg,
32353235
ArrayRef<const Expr *> Args) {
3236-
auto GetArgAt = [&](int Idx) -> Expr * {
3236+
if (!FD || Args.empty())
3237+
return;
3238+
auto GetArgAt = [&](int Idx) -> const Expr * {
32373239
if (Idx == LifetimeCaptureByAttr::GLOBAL ||
32383240
Idx == LifetimeCaptureByAttr::UNKNOWN)
32393241
return nullptr;
32403242
if (IsMemberFunction && Idx == 0)
3241-
return const_cast<Expr *>(ThisArg);
3242-
return const_cast<Expr *>(Args[Idx - int(IsMemberFunction)]);
3243+
return ThisArg;
3244+
return Args[Idx - IsMemberFunction];
32433245
};
3244-
for (unsigned I = 0; I < FD->getNumParams(); ++I) {
3245-
auto *CapturedByAttr =
3246-
FD->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>();
3247-
if (!CapturedByAttr)
3248-
continue;
3249-
for (int CapturingParamIdx : CapturedByAttr->params()) {
3250-
Expr *Capturing = GetArgAt(CapturingParamIdx);
3251-
Expr *Captured = GetArgAt(I + IsMemberFunction);
3246+
auto HandleCaptureByAttr = [&](const LifetimeCaptureByAttr *Attr,
3247+
unsigned ArgIdx) {
3248+
if (!Attr)
3249+
return;
3250+
Expr *Captured = const_cast<Expr *>(GetArgAt(ArgIdx));
3251+
for (int CapturingParamIdx : Attr->params()) {
3252+
Expr *Capturing = const_cast<Expr *>(GetArgAt(CapturingParamIdx));
32523253
CapturingEntity CE{Capturing};
32533254
// Ensure that 'Captured' outlives the 'Capturing' entity.
32543255
checkExprLifetime(*this, CE, Captured);
32553256
}
3256-
}
3257-
// Check when the 'this' object is captured.
3257+
};
3258+
for (unsigned I = 0; I < FD->getNumParams(); ++I)
3259+
HandleCaptureByAttr(FD->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>(),
3260+
I + IsMemberFunction);
3261+
// Check when the implicit object param is captured.
32583262
if (IsMemberFunction) {
32593263
TypeSourceInfo *TSI = FD->getTypeSourceInfo();
32603264
if (!TSI)
32613265
return;
32623266
AttributedTypeLoc ATL;
32633267
for (TypeLoc TL = TSI->getTypeLoc();
32643268
(ATL = TL.getAsAdjusted<AttributedTypeLoc>());
3265-
TL = ATL.getModifiedLoc()) {
3266-
auto *CapturedByAttr = ATL.getAttrAs<LifetimeCaptureByAttr>();
3267-
if (!CapturedByAttr)
3268-
continue;
3269-
Expr *Captured = GetArgAt(0);
3270-
for (int CapturingParamIdx : CapturedByAttr->params()) {
3271-
Expr *Capturing = GetArgAt(CapturingParamIdx);
3272-
CapturingEntity CE{Capturing};
3273-
checkExprLifetime(*this, CE, Captured);
3274-
}
3275-
}
3269+
TL = ATL.getModifiedLoc())
3270+
HandleCaptureByAttr(ATL.getAttrAs<LifetimeCaptureByAttr>(), 0);
32763271
}
32773272
}
32783273

clang/test/Sema/warn-lifetime-analysis-capture-by.cpp

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ void noCaptureInt(int i [[clang::lifetime_capture_by(x)]], X &x);
1717
std::string_view substr(const std::string& s [[clang::lifetimebound]]);
1818
std::string_view strcopy(const std::string& s);
1919

20-
void captureSV(std::string_view s [[clang::lifetime_capture_by(x)]], X &x);
21-
void captureRValSV(std::string_view &&sv [[clang::lifetime_capture_by(x)]], X &x);
22-
void noCaptureSV(std::string_view sv, X &x);
23-
void captureS(const std::string &s [[clang::lifetime_capture_by(x)]], X &x);
24-
void captureRValS(std::string &&s [[clang::lifetime_capture_by(x)]], X &x);
20+
void captureStringView(std::string_view s [[clang::lifetime_capture_by(x)]], X &x);
21+
void captureRValStringView(std::string_view &&sv [[clang::lifetime_capture_by(x)]], X &x);
22+
void noCaptureStringView(std::string_view sv, X &x);
23+
void captureString(const std::string &s [[clang::lifetime_capture_by(x)]], X &x);
24+
void captureRValString(std::string &&s [[clang::lifetime_capture_by(x)]], X &x);
2525

2626
const std::string& getLB(const std::string &s [[clang::lifetimebound]]);
2727
const std::string& getLB(std::string_view sv [[clang::lifetimebound]]);
@@ -38,8 +38,8 @@ void captureByGlobal(std::string_view s [[clang::lifetime_capture_by(global)]]);
3838
void captureByUnknown(std::string_view s [[clang::lifetime_capture_by(unknown)]]);
3939

4040
void use() {
41-
std::string_view local_sv;
42-
std::string local_s;
41+
std::string_view local_string_view;
42+
std::string local_string;
4343
X x;
4444
// Capture an 'int'.
4545
int local;
@@ -51,34 +51,34 @@ void use() {
5151
noCaptureInt(local, x);
5252

5353
// Capture using std::string_view.
54-
captureSV(local_sv, x);
55-
captureSV(std::string(), // expected-warning {{object whose reference is captured by 'x'}}
54+
captureStringView(local_string_view, x);
55+
captureStringView(std::string(), // expected-warning {{object whose reference is captured by 'x'}}
5656
x);
57-
captureSV(substr(
57+
captureStringView(substr(
5858
std::string() // expected-warning {{object whose reference is captured by 'x'}}
5959
), x);
60-
captureSV(substr(local_s), x);
61-
captureSV(strcopy(std::string()), x);
62-
captureRValSV(std::move(local_sv), x);
63-
captureRValSV(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}}
64-
captureRValSV(std::string_view{"abcd"}, x);
65-
captureRValSV(substr(local_s), x);
66-
captureRValSV(substr(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}}
67-
captureRValSV(strcopy(std::string()), x);
68-
noCaptureSV(local_sv, x);
69-
noCaptureSV(std::string(), x);
70-
noCaptureSV(substr(std::string()), x);
60+
captureStringView(substr(local_string), x);
61+
captureStringView(strcopy(std::string()), x);
62+
captureRValStringView(std::move(local_string_view), x);
63+
captureRValStringView(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}}
64+
captureRValStringView(std::string_view{"abcd"}, x);
65+
captureRValStringView(substr(local_string), x);
66+
captureRValStringView(substr(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}}
67+
captureRValStringView(strcopy(std::string()), x);
68+
noCaptureStringView(local_string_view, x);
69+
noCaptureStringView(std::string(), x);
70+
noCaptureStringView(substr(std::string()), x);
7171

7272
// Capture using std::string.
73-
captureS(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}}
74-
captureS(local_s, x);
75-
captureRValS(std::move(local_s), x);
76-
captureRValS(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}}
73+
captureString(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}}
74+
captureString(local_string, x);
75+
captureRValString(std::move(local_string), x);
76+
captureRValString(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}}
7777

7878
// Capture with lifetimebound.
79-
captureSV(getLB(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}}
80-
captureSV(getLB(substr(std::string())), x); // expected-warning {{object whose reference is captured by 'x'}}
81-
captureSV(getLB(getLB(
79+
captureStringView(getLB(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}}
80+
captureStringView(getLB(substr(std::string())), x); // expected-warning {{object whose reference is captured by 'x'}}
81+
captureStringView(getLB(getLB(
8282
std::string() // expected-warning {{object whose reference is captured by 'x'}}
8383
)), x);
8484
capturePointer(getPointerLB(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}}
@@ -101,14 +101,23 @@ void use() {
101101
// capture by global.
102102
captureByGlobal(std::string()); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}}
103103
captureByGlobal(substr(std::string())); // expected-warning {{captured}}
104-
captureByGlobal(local_s);
105-
captureByGlobal(local_sv);
104+
captureByGlobal(local_string);
105+
captureByGlobal(local_string_view);
106106

107107
// // capture by unknown.
108108
captureByGlobal(std::string()); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}}
109109
captureByGlobal(substr(std::string())); // expected-warning {{captured}}
110-
captureByGlobal(local_s);
111-
captureByGlobal(local_sv);
110+
captureByGlobal(local_string);
111+
captureByGlobal(local_string_view);
112+
}
113+
114+
void captureDefaultArg(X &x, std::string_view s [[clang::lifetime_capture_by(x)]] = std::string());
115+
void useCaptureDefaultArg() {
116+
X x;
117+
captureDefaultArg(x); // FIXME: Diagnose temporary default arg.
118+
captureDefaultArg(x, std::string("temp")); // expected-warning {{captured}}
119+
std::string local;
120+
captureDefaultArg(x, local);
112121
}
113122

114123
template<typename T> struct IsPointerLikeTypeImpl : std::false_type {};
@@ -189,13 +198,16 @@ void container_of_pointers() {
189198
std::optional<std::string_view> optionalSV;
190199
vsv.push_back(optionalSV.value());
191200
vsv.push_back(getOptionalS().value()); // expected-warning {{object whose reference is captured by 'vsv'}}
192-
vsv.push_back(getOptionalSV().value());
193-
vsv.push_back(getOptionalMySV().value());
201+
202+
// FIXME: Following 2 cases are false positives:
203+
vsv.push_back(getOptionalSV().value()); // expected-warning {{object whose reference}}
204+
vsv.push_back(getOptionalMySV().value()); // expected-warning {{object whose reference}}
194205

195206
// (maybe) FIXME: We may choose to diagnose the following case.
196207
// This happens because 'MyStringViewNotPointer' is not marked as a [[gsl::Pointer]] but is derived from one.
197208
vsv.push_back(getOptionalMySVNotP().value()); // expected-warning {{object whose reference is captured by 'vsv'}}
198209
}
210+
199211
namespace temporary_views {
200212
void capture1(std::string_view s [[clang::lifetime_capture_by(x)]], std::vector<std::string_view>& x);
201213

@@ -217,4 +229,4 @@ void test1() {
217229
capture3(std::string_view(), x3);
218230
capture3(std::string(), x3); // expected-warning {{captured by 'x3'}}
219231
}
220-
}
232+
}

0 commit comments

Comments
 (0)