Skip to content

Commit 8c22f56

Browse files
authored
[Fix] Speedup -Wunsafe-buffer-usage when using clang modules. (llvm#127161)
Each piece of code should have analysis run on it precisely once. However, if you build a module, and then build another module depending on it, the header file of the module you depend on will have `-Wunsafe-buffer-usage` run on it twice. This normally isn't a huge issue, but in the case of using the standard library as a module, simply adding the line `#include <cstddef>` increases compile times by 900ms (from 100ms to 1 second) on my machine. I believe this is because the standard library has massive modules, of which only a small part is used (the AST is ~700k lines), and because if what I've been told is correct, the AST is lazily generated, and `-Wunsafe-buffer-usage` forces it to be evaluated every time. See https://issues.chromium.org/issues/351909443 for details and benchmarks.
1 parent c3959f2 commit 8c22f56

File tree

2 files changed

+23
-23
lines changed

2 files changed

+23
-23
lines changed

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,14 +2532,25 @@ static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) {
25322532
class CallableVisitor : public DynamicRecursiveASTVisitor {
25332533
private:
25342534
llvm::function_ref<void(const Decl *)> Callback;
2535+
const Module *const TUModule;
25352536

25362537
public:
2537-
CallableVisitor(llvm::function_ref<void(const Decl *)> Callback)
2538-
: Callback(Callback) {
2538+
CallableVisitor(llvm::function_ref<void(const Decl *)> Callback,
2539+
const Module *const TUModule)
2540+
: Callback(Callback), TUModule(TUModule) {
25392541
ShouldVisitTemplateInstantiations = true;
25402542
ShouldVisitImplicitCode = false;
25412543
}
25422544

2545+
bool TraverseDecl(Decl *Node) override {
2546+
// For performance reasons, only validate the current translation unit's
2547+
// module, and not modules it depends on.
2548+
// See https://issues.chromium.org/issues/351909443 for details.
2549+
if (Node && Node->getOwningModule() == TUModule)
2550+
return DynamicRecursiveASTVisitor::TraverseDecl(Node);
2551+
return true;
2552+
}
2553+
25432554
bool VisitFunctionDecl(FunctionDecl *Node) override {
25442555
if (cast<DeclContext>(Node)->isDependentContext())
25452556
return true; // Not to analyze dependent decl
@@ -2622,7 +2633,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
26222633
SourceLocation()) ||
26232634
(!Diags.isIgnored(diag::warn_unsafe_buffer_libc_call, SourceLocation()) &&
26242635
S.getLangOpts().CPlusPlus /* only warn about libc calls in C++ */)) {
2625-
CallableVisitor(CallAnalyzers).TraverseTranslationUnitDecl(TU);
2636+
CallableVisitor(CallAnalyzers, TU->getOwningModule())
2637+
.TraverseTranslationUnitDecl(TU);
26262638
}
26272639
}
26282640

clang/test/Modules/safe_buffers_optout.cpp

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,10 @@ int textual(int *p) {
9595
// `safe_buffers_test_optout`, which uses another top-level module
9696
// `safe_buffers_test_base`. (So the module dependencies form a DAG.)
9797

98-
// No expected warnings from base.h because base.h is a separate
99-
// module and in a separate TU that is not textually included. The
100-
// explicit command that builds base.h has no `-Wunsafe-buffer-usage`.
101-
102-
// [email protected]:3{{unsafe buffer access}}
103-
// [email protected]:3{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
104-
// expected-warning@test_sub1.h:5{{unsafe buffer access}}
105-
// expected-note@test_sub1.h:5{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
106-
// expected-warning@test_sub1.h:14{{unsafe buffer access}}
107-
// expected-note@test_sub1.h:14{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
108-
// expected-warning@test_sub2.h:5{{unsafe buffer access}}
109-
// expected-note@test_sub2.h:5{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
98+
// No expected warnings from base.h, test_sub1, or test_sub2 because they are
99+
// in seperate modules, and the explicit commands that builds them have no
100+
// `-Wunsafe-buffer-usage`.
101+
110102
int foo(int * p) {
111103
int x = p[5]; // expected-warning{{unsafe buffer access}} expected-note{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
112104
#pragma clang unsafe_buffer_usage begin
@@ -129,14 +121,10 @@ int foo(int * p) {
129121
// `safe_buffers_test_optout`, which uses another top-level module
130122
// `safe_buffers_test_base`. (So the module dependencies form a DAG.)
131123

132-
// [email protected]:3{{unsafe buffer access}}
133-
// [email protected]:3{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
134-
// expected-warning@test_sub1.h:5{{unsafe buffer access}}
135-
// expected-note@test_sub1.h:5{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
136-
// expected-warning@test_sub1.h:14{{unsafe buffer access}}
137-
// expected-note@test_sub1.h:14{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
138-
// expected-warning@test_sub2.h:5{{unsafe buffer access}}
139-
// expected-note@test_sub2.h:5{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
124+
// No expected warnings from base.h, test_sub1, or test_sub2 because they are
125+
// in seperate modules, and the explicit commands that builds them have no
126+
// `-Wunsafe-buffer-usage`.
127+
140128
int foo(int * p) {
141129
int x = p[5]; // expected-warning{{unsafe buffer access}} expected-note{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
142130
#pragma clang unsafe_buffer_usage begin

0 commit comments

Comments
 (0)