Skip to content

Commit 0456acb

Browse files
committed
[clang/Sema] Follow-up for fix of non-deterministic order of -Wunused-variable diagnostic
Commit `371883f46dc23f8464cbf578e2d12a4f92e61917` caused a noticeable compile-time regression (about 0.4% geomean at -O0): http://llvm-compile-time-tracker.com/compare.php?from=92233159035d1b50face95d886901cf99035bd99&to=371883f46dc23f8464cbf578e2d12a4f92e61917&stat=instructions To address this switch `Scope::DeclSetTy` back to a `SmallPtrSet` and change `Sema::ActOnPopScope` to explicitly order the diagnostics that this function emits. Differential Revision: https://reviews.llvm.org/D135490
1 parent c49cde6 commit 0456acb

File tree

3 files changed

+71
-22
lines changed

3 files changed

+71
-22
lines changed

clang/include/clang/Sema/Scope.h

+3-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include "clang/AST/Decl.h"
1717
#include "clang/Basic/Diagnostic.h"
1818
#include "llvm/ADT/PointerIntPair.h"
19-
#include "llvm/ADT/SetVector.h"
2019
#include "llvm/ADT/SmallPtrSet.h"
2120
#include "llvm/ADT/SmallVector.h"
2221
#include "llvm/ADT/iterator_range.h"
@@ -197,7 +196,7 @@ class Scope {
197196
/// popped, these declarations are removed from the IdentifierTable's notion
198197
/// of current declaration. It is up to the current Action implementation to
199198
/// implement these semantics.
200-
using DeclSetTy = llvm::SmallSetVector<Decl *, 32>;
199+
using DeclSetTy = llvm::SmallPtrSet<Decl *, 32>;
201200
DeclSetTy DeclsInScope;
202201

203202
/// The DeclContext with which this scope is associated. For
@@ -322,7 +321,7 @@ class Scope {
322321
DeclsInScope.insert(D);
323322
}
324323

325-
void RemoveDecl(Decl *D) { DeclsInScope.remove(D); }
324+
void RemoveDecl(Decl *D) { DeclsInScope.erase(D); }
326325

327326
void incrementMSManglingNumber() {
328327
if (Scope *MSLMP = getMSLastManglingParent()) {
@@ -350,9 +349,7 @@ class Scope {
350349

351350
/// isDeclScope - Return true if this is the scope that the specified decl is
352351
/// declared in.
353-
bool isDeclScope(const Decl *D) const {
354-
return DeclsInScope.contains(const_cast<Decl *>(D));
355-
}
352+
bool isDeclScope(const Decl *D) const { return DeclsInScope.contains(D); }
356353

357354
/// Get the entity corresponding to this scope.
358355
DeclContext *getEntity() const {

clang/include/clang/Sema/Sema.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -5221,15 +5221,21 @@ class Sema final {
52215221
/// of it.
52225222
void MarkUnusedFileScopedDecl(const DeclaratorDecl *D);
52235223

5224+
typedef llvm::function_ref<void(SourceLocation Loc, PartialDiagnostic PD)>
5225+
DiagReceiverTy;
5226+
52245227
/// DiagnoseUnusedExprResult - If the statement passed in is an expression
52255228
/// whose result is unused, warn.
52265229
void DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID);
52275230
void DiagnoseUnusedNestedTypedefs(const RecordDecl *D);
5231+
void DiagnoseUnusedNestedTypedefs(const RecordDecl *D,
5232+
DiagReceiverTy DiagReceiver);
52285233
void DiagnoseUnusedDecl(const NamedDecl *ND);
5234+
void DiagnoseUnusedDecl(const NamedDecl *ND, DiagReceiverTy DiagReceiver);
52295235

52305236
/// If VD is set but not otherwise used, diagnose, for a parameter or a
52315237
/// variable.
5232-
void DiagnoseUnusedButSetDecl(const VarDecl *VD);
5238+
void DiagnoseUnusedButSetDecl(const VarDecl *VD, DiagReceiverTy DiagReceiver);
52335239

52345240
/// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null
52355241
/// statement as a \p Body, and it is located on the same line.

clang/lib/Sema/SemaDecl.cpp

+61-15
Original file line numberDiff line numberDiff line change
@@ -2091,20 +2091,31 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
20912091
}
20922092

20932093
void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) {
2094+
DiagnoseUnusedNestedTypedefs(
2095+
D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
2096+
}
2097+
2098+
void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D,
2099+
DiagReceiverTy DiagReceiver) {
20942100
if (D->getTypeForDecl()->isDependentType())
20952101
return;
20962102

20972103
for (auto *TmpD : D->decls()) {
20982104
if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD))
2099-
DiagnoseUnusedDecl(T);
2105+
DiagnoseUnusedDecl(T, DiagReceiver);
21002106
else if(const auto *R = dyn_cast<RecordDecl>(TmpD))
2101-
DiagnoseUnusedNestedTypedefs(R);
2107+
DiagnoseUnusedNestedTypedefs(R, DiagReceiver);
21022108
}
21032109
}
21042110

2111+
void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
2112+
DiagnoseUnusedDecl(
2113+
D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
2114+
}
2115+
21052116
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
21062117
/// unless they are marked attr(unused).
2107-
void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
2118+
void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver) {
21082119
if (!ShouldDiagnoseUnusedDecl(D))
21092120
return;
21102121

@@ -2126,10 +2137,11 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
21262137
else
21272138
DiagID = diag::warn_unused_variable;
21282139

2129-
Diag(D->getLocation(), DiagID) << D << Hint;
2140+
DiagReceiver(D->getLocation(), PDiag(DiagID) << D << Hint);
21302141
}
21312142

2132-
void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
2143+
void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD,
2144+
DiagReceiverTy DiagReceiver) {
21332145
// If it's not referenced, it can't be set. If it has the Cleanup attribute,
21342146
// it's not really unused.
21352147
if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr<UnusedAttr>() ||
@@ -2175,10 +2187,11 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
21752187
return;
21762188
unsigned DiagID = isa<ParmVarDecl>(VD) ? diag::warn_unused_but_set_parameter
21772189
: diag::warn_unused_but_set_variable;
2178-
Diag(VD->getLocation(), DiagID) << VD;
2190+
DiagReceiver(VD->getLocation(), PDiag(DiagID) << VD);
21792191
}
21802192

2181-
static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
2193+
static void CheckPoppedLabel(LabelDecl *L, Sema &S,
2194+
Sema::DiagReceiverTy DiagReceiver) {
21822195
// Verify that we have no forward references left. If so, there was a goto
21832196
// or address of a label taken, but no definition of it. Label fwd
21842197
// definitions are indicated with a null substmt which is also not a resolved
@@ -2189,7 +2202,8 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
21892202
else
21902203
Diagnose = L->getStmt() == nullptr;
21912204
if (Diagnose)
2192-
S.Diag(L->getLocation(), diag::err_undeclared_label_use) << L;
2205+
DiagReceiver(L->getLocation(), S.PDiag(diag::err_undeclared_label_use)
2206+
<< L);
21932207
}
21942208

21952209
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
@@ -2199,6 +2213,24 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
21992213
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
22002214
"Scope shouldn't contain decls!");
22012215

2216+
/// We visit the decls in non-deterministic order, but we want diagnostics
2217+
/// emitted in deterministic order. Collect any diagnostic that may be emitted
2218+
/// and sort the diagnostics before emitting them, after we visited all decls.
2219+
struct LocAndDiag {
2220+
SourceLocation Loc;
2221+
Optional<SourceLocation> PreviousDeclLoc;
2222+
PartialDiagnostic PD;
2223+
};
2224+
SmallVector<LocAndDiag, 16> DeclDiags;
2225+
auto addDiag = [&DeclDiags](SourceLocation Loc, PartialDiagnostic PD) {
2226+
DeclDiags.push_back(LocAndDiag{Loc, None, std::move(PD)});
2227+
};
2228+
auto addDiagWithPrev = [&DeclDiags](SourceLocation Loc,
2229+
SourceLocation PreviousDeclLoc,
2230+
PartialDiagnostic PD) {
2231+
DeclDiags.push_back(LocAndDiag{Loc, PreviousDeclLoc, std::move(PD)});
2232+
};
2233+
22022234
for (auto *TmpD : S->decls()) {
22032235
assert(TmpD && "This decl didn't get pushed??");
22042236

@@ -2207,11 +2239,11 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
22072239

22082240
// Diagnose unused variables in this scope.
22092241
if (!S->hasUnrecoverableErrorOccurred()) {
2210-
DiagnoseUnusedDecl(D);
2242+
DiagnoseUnusedDecl(D, addDiag);
22112243
if (const auto *RD = dyn_cast<RecordDecl>(D))
2212-
DiagnoseUnusedNestedTypedefs(RD);
2244+
DiagnoseUnusedNestedTypedefs(RD, addDiag);
22132245
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
2214-
DiagnoseUnusedButSetDecl(VD);
2246+
DiagnoseUnusedButSetDecl(VD, addDiag);
22152247
RefsMinusAssignments.erase(VD);
22162248
}
22172249
}
@@ -2220,21 +2252,35 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
22202252

22212253
// If this was a forward reference to a label, verify it was defined.
22222254
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
2223-
CheckPoppedLabel(LD, *this);
2255+
CheckPoppedLabel(LD, *this, addDiag);
22242256

22252257
// Remove this name from our lexical scope, and warn on it if we haven't
22262258
// already.
22272259
IdResolver.RemoveDecl(D);
22282260
auto ShadowI = ShadowingDecls.find(D);
22292261
if (ShadowI != ShadowingDecls.end()) {
22302262
if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) {
2231-
Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field)
2232-
<< D << FD << FD->getParent();
2233-
Diag(FD->getLocation(), diag::note_previous_declaration);
2263+
addDiagWithPrev(D->getLocation(), FD->getLocation(),
2264+
PDiag(diag::warn_ctor_parm_shadows_field)
2265+
<< D << FD << FD->getParent());
22342266
}
22352267
ShadowingDecls.erase(ShadowI);
22362268
}
22372269
}
2270+
2271+
llvm::sort(DeclDiags,
2272+
[](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool {
2273+
// The particular order for diagnostics is not important, as long
2274+
// as the order is deterministic. Using the raw location is going
2275+
// to generally be in source order unless there are macro
2276+
// expansions involved.
2277+
return LHS.Loc.getRawEncoding() < RHS.Loc.getRawEncoding();
2278+
});
2279+
for (const LocAndDiag &D : DeclDiags) {
2280+
Diag(D.Loc, D.PD);
2281+
if (D.PreviousDeclLoc)
2282+
Diag(*D.PreviousDeclLoc, diag::note_previous_declaration);
2283+
}
22382284
}
22392285

22402286
/// Look for an Objective-C class in the translation unit.

0 commit comments

Comments
 (0)