Skip to content

Commit 01a1e26

Browse files
Doug Wyattcjappl
authored andcommitted
CallableInfo doesn't need to cache the name.
Clean up traversal of constructor initializers and implicit destructors (with test).
1 parent 66085a5 commit 01a1e26

File tree

2 files changed

+62
-60
lines changed

2 files changed

+62
-60
lines changed

clang/lib/Sema/EffectAnalysis.cpp

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ struct CallableInfo {
199199
// FunctionDecl if CallType::Function or Virtual
200200
// BlockDecl if CallType::Block
201201
const Decl *CDecl;
202-
mutable std::optional<std::string> MaybeName;
203202
SpecialFuncType FuncType = SpecialFuncType::None;
204203
EffectSet Effects;
205204
CallType CType = CallType::Unknown;
@@ -247,20 +246,17 @@ struct CallableInfo {
247246

248247
/// Generate a name for logging and diagnostics.
249248
std::string name(Sema &Sem) const {
250-
if (!MaybeName) {
251-
std::string Name;
252-
llvm::raw_string_ostream OS(Name);
253-
254-
if (auto *FD = dyn_cast<FunctionDecl>(CDecl))
255-
FD->getNameForDiagnostic(OS, Sem.getPrintingPolicy(),
256-
/*Qualified=*/true);
257-
else if (auto *BD = dyn_cast<BlockDecl>(CDecl))
258-
OS << "(block " << BD->getBlockManglingNumber() << ")";
259-
else if (auto *VD = dyn_cast<NamedDecl>(CDecl))
260-
VD->printQualifiedName(OS);
261-
MaybeName = Name;
262-
}
263-
return *MaybeName;
249+
std::string Name;
250+
llvm::raw_string_ostream OS(Name);
251+
252+
if (auto *FD = dyn_cast<FunctionDecl>(CDecl))
253+
FD->getNameForDiagnostic(OS, Sem.getPrintingPolicy(),
254+
/*Qualified=*/true);
255+
else if (auto *BD = dyn_cast<BlockDecl>(CDecl))
256+
OS << "(block " << BD->getBlockManglingNumber() << ")";
257+
else if (auto *VD = dyn_cast<NamedDecl>(CDecl))
258+
VD->printQualifiedName(OS);
259+
return Name;
264260
}
265261
};
266262

@@ -955,17 +951,10 @@ class Analyzer {
955951

956952
// -- Entry point --
957953
void run() {
958-
// The target function itself may have some implicit code paths beyond the
959-
// body: member and base constructors and destructors. Visit these first.
960-
if (const auto *FD = dyn_cast<const FunctionDecl>(CurrentCaller.CDecl)) {
961-
if (auto *Ctor = dyn_cast<CXXConstructorDecl>(FD)) {
962-
for (const CXXCtorInitializer *Initer : Ctor->inits())
963-
if (Expr *Init = Initer->getInit())
964-
VisitStmt(Init);
965-
} else if (auto *Dtor = dyn_cast<CXXDestructorDecl>(FD))
966-
followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor);
967-
}
968-
// else could be BlockDecl
954+
// The target function may have implicit code paths beyond the
955+
// body: member and base destructors. Visit these first.
956+
if (auto *Dtor = dyn_cast<CXXDestructorDecl>(CurrentCaller.CDecl))
957+
followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor);
969958

970959
// Do an AST traversal of the function/block body
971960
TraverseDecl(const_cast<Decl *>(CurrentCaller.CDecl));
@@ -1043,18 +1032,18 @@ class Analyzer {
10431032
void followDestructor(const CXXRecordDecl *Rec,
10441033
const CXXDestructorDecl *Dtor) {
10451034
for (const FieldDecl *Field : Rec->fields())
1046-
followTypeDtor(Field->getType());
1035+
followTypeDtor(Field->getType(), Dtor);
10471036

10481037
if (const auto *Class = dyn_cast<CXXRecordDecl>(Rec)) {
10491038
for (const CXXBaseSpecifier &Base : Class->bases())
1050-
followTypeDtor(Base.getType());
1039+
followTypeDtor(Base.getType(), Dtor);
10511040

10521041
for (const CXXBaseSpecifier &Base : Class->vbases())
1053-
followTypeDtor(Base.getType());
1042+
followTypeDtor(Base.getType(), Dtor);
10541043
}
10551044
}
10561045

1057-
void followTypeDtor(QualType QT) {
1046+
void followTypeDtor(QualType QT, const CXXDestructorDecl *OuterDtor) {
10581047
const Type *Ty = QT.getTypePtr();
10591048
while (Ty->isArrayType()) {
10601049
const ArrayType *Arr = Ty->getAsArrayTypeUnsafe();
@@ -1066,7 +1055,7 @@ class Analyzer {
10661055
if (const CXXRecordDecl *Class = Ty->getAsCXXRecordDecl()) {
10671056
if (CXXDestructorDecl *Dtor = Class->getDestructor()) {
10681057
CallableInfo CI(Outer.Sem, *Dtor);
1069-
followCall(CI, Dtor->getLocation());
1058+
followCall(CI, OuterDtor->getLocation());
10701059
}
10711060
}
10721061
}

clang/test/Sema/attr-nonblocking-constraints.cpp

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77

88
// --- CONSTRAINTS ---
99

10-
void nl1() [[clang::nonblocking]]
10+
void nb1() [[clang::nonblocking]]
1111
{
1212
int *pInt = new int; // expected-warning {{'nonblocking' function must not allocate or deallocate memory}}
1313
delete pInt; // expected-warning {{'nonblocking' function must not allocate or deallocate memory}}
1414
}
1515

16-
void nl2() [[clang::nonblocking]]
16+
void nb2() [[clang::nonblocking]]
1717
{
1818
static int global; // expected-warning {{'nonblocking' function must not have static locals}}
1919
}
2020

21-
void nl3() [[clang::nonblocking]]
21+
void nb3() [[clang::nonblocking]]
2222
{
2323
try {
2424
throw 42; // expected-warning {{'nonblocking' function must not throw or catch exceptions}}
@@ -27,35 +27,35 @@ void nl3() [[clang::nonblocking]]
2727
}
2828
}
2929

30-
void nl4_inline() {}
31-
void nl4_not_inline(); // expected-note {{function cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
30+
void nb4_inline() {}
31+
void nb4_not_inline(); // expected-note {{function cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
3232

33-
void nl4() [[clang::nonblocking]]
33+
void nb4() [[clang::nonblocking]]
3434
{
35-
nl4_inline(); // OK
36-
nl4_not_inline(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
35+
nb4_inline(); // OK
36+
nb4_not_inline(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
3737
}
3838

3939

4040
struct HasVirtual {
4141
virtual void unsafe(); // expected-note {{virtual method cannot be inferred 'nonblocking'}}
4242
};
4343

44-
void nl5() [[clang::nonblocking]]
44+
void nb5() [[clang::nonblocking]]
4545
{
4646
HasVirtual hv;
4747
hv.unsafe(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
4848
}
4949

50-
void nl6_unsafe(); // expected-note {{function cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
51-
void nl6_transitively_unsafe()
50+
void nb6_unsafe(); // expected-note {{function cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
51+
void nb6_transitively_unsafe()
5252
{
53-
nl6_unsafe(); // expected-note {{function cannot be inferred 'nonblocking' because it calls non-'nonblocking' function}}
53+
nb6_unsafe(); // expected-note {{function cannot be inferred 'nonblocking' because it calls non-'nonblocking' function}}
5454
}
5555

56-
void nl6() [[clang::nonblocking]]
56+
void nb6() [[clang::nonblocking]]
5757
{
58-
nl6_transitively_unsafe(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
58+
nb6_transitively_unsafe(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
5959
}
6060

6161
thread_local int tl_var{ 42 };
@@ -65,15 +65,15 @@ bool tl_test() [[clang::nonblocking]]
6565
return tl_var > 0; // expected-warning {{'nonblocking' function must not use thread-local variables}}
6666
}
6767

68-
void nl7()
68+
void nb7()
6969
{
7070
// Make sure we verify blocks
7171
auto blk = ^() [[clang::nonblocking]] {
7272
throw 42; // expected-warning {{'nonblocking' function must not throw or catch exceptions}}
7373
};
7474
}
7575

76-
void nl8()
76+
void nb8()
7777
{
7878
// Make sure we verify lambdas
7979
auto lambda = []() [[clang::nonblocking]] {
@@ -111,7 +111,7 @@ void nl8()
111111
}
112112
};
113113

114-
void nl9() [[clang::nonblocking]]
114+
void nb9() [[clang::nonblocking]]
115115
{
116116
Adder<int>::add_explicit(1, 2);
117117
Adder<int>::add_implicit(1, 2);
@@ -121,7 +121,7 @@ void nl9() [[clang::nonblocking]]
121121
expected-note {{in template expansion here}}
122122
}
123123

124-
void nl10(
124+
void nb10(
125125
void (*fp1)(), // expected-note {{function pointer cannot be inferred 'nonblocking'}}
126126
void (*fp2)() [[clang::nonblocking]]
127127
) [[clang::nonblocking]]
@@ -131,20 +131,20 @@ void nl10(
131131
}
132132

133133
// Interactions with nonblocking(false)
134-
void nl11_no_inference_1() [[clang::nonblocking(false)]] // expected-note {{function does not permit inference of 'nonblocking'}}
134+
void nb11_no_inference_1() [[clang::nonblocking(false)]] // expected-note {{function does not permit inference of 'nonblocking'}}
135135
{
136136
}
137-
void nl11_no_inference_2() [[clang::nonblocking(false)]]; // expected-note {{function does not permit inference of 'nonblocking'}}
137+
void nb11_no_inference_2() [[clang::nonblocking(false)]]; // expected-note {{function does not permit inference of 'nonblocking'}}
138138

139139
template <bool V>
140140
struct ComputedNB {
141141
void method() [[clang::nonblocking(V)]]; // expected-note {{function does not permit inference of 'nonblocking'}}
142142
};
143143

144-
void nl11() [[clang::nonblocking]]
144+
void nb11() [[clang::nonblocking]]
145145
{
146-
nl11_no_inference_1(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
147-
nl11_no_inference_2(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
146+
nb11_no_inference_1(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
147+
nb11_no_inference_2(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function}}
148148

149149
ComputedNB<true> CNB_true;
150150
CNB_true.method();
@@ -154,11 +154,11 @@ void nl11() [[clang::nonblocking]]
154154
}
155155

156156
// Verify that when attached to a redeclaration, the attribute successfully attaches.
157-
void nl12() {
157+
void nb12() {
158158
static int x; // expected-warning {{'nonblocking' function must not have static locals}}
159159
}
160-
void nl12() [[clang::nonblocking]];
161-
void nl13() [[clang::nonblocking]] { nl12(); }
160+
void nb12() [[clang::nonblocking]];
161+
void nb13() [[clang::nonblocking]] { nb12(); }
162162

163163
// C++ member function pointers
164164
struct PTMFTester {
@@ -175,21 +175,34 @@ void PTMFTester::convert() [[clang::nonblocking]]
175175
}
176176

177177
// Block variables
178-
void nl17(void (^blk)() [[clang::nonblocking]]) [[clang::nonblocking]] {
178+
void nb17(void (^blk)() [[clang::nonblocking]]) [[clang::nonblocking]] {
179179
blk();
180180
}
181181

182182
// References to blocks
183-
void nl18(void (^block)() [[clang::nonblocking]]) [[clang::nonblocking]]
183+
void nb18(void (^block)() [[clang::nonblocking]]) [[clang::nonblocking]]
184184
{
185185
auto &ref = block;
186186
ref();
187187
}
188188

189+
// Verify traversal of implicit code paths - constructors and destructors.
190+
struct Unsafe {
191+
static void problem1(); // expected-note {{function cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
192+
static void problem2(); // expected-note {{function cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
193+
194+
Unsafe() { problem1(); } // expected-note {{function cannot be inferred 'nonblocking' because it calls non-'nonblocking' function 'Unsafe::problem1'}}
195+
~Unsafe() { problem2(); } // expected-note {{function cannot be inferred 'nonblocking' because it calls non-'nonblocking' function 'Unsafe::problem2'}}
196+
};
197+
198+
struct DerivedFromUnsafe : public Unsafe {
199+
DerivedFromUnsafe() [[clang::nonblocking]] {} // expected-warning {{'nonblocking' function must not call non-'nonblocking' function 'Unsafe::Unsafe'}}
200+
~DerivedFromUnsafe() [[clang::nonblocking]] {} // expected-warning {{'nonblocking' function must not call non-'nonblocking' function 'Unsafe::~Unsafe'}}
201+
};
189202

190203
// --- nonblocking implies noexcept ---
191204
#pragma clang diagnostic warning "-Wperf-constraint-implies-noexcept"
192205

193-
void nl19() [[clang::nonblocking]] // expected-warning {{'nonblocking' function should be declared noexcept}}
206+
void nb19() [[clang::nonblocking]] // expected-warning {{'nonblocking' function should be declared noexcept}}
194207
{
195208
}

0 commit comments

Comments
 (0)