@@ -2091,20 +2091,31 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
2091
2091
}
2092
2092
2093
2093
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) {
2094
2100
if (D->getTypeForDecl()->isDependentType())
2095
2101
return;
2096
2102
2097
2103
for (auto *TmpD : D->decls()) {
2098
2104
if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD))
2099
- DiagnoseUnusedDecl(T);
2105
+ DiagnoseUnusedDecl(T, DiagReceiver );
2100
2106
else if(const auto *R = dyn_cast<RecordDecl>(TmpD))
2101
- DiagnoseUnusedNestedTypedefs(R);
2107
+ DiagnoseUnusedNestedTypedefs(R, DiagReceiver );
2102
2108
}
2103
2109
}
2104
2110
2111
+ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
2112
+ DiagnoseUnusedDecl(
2113
+ D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
2114
+ }
2115
+
2105
2116
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
2106
2117
/// unless they are marked attr(unused).
2107
- void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
2118
+ void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver ) {
2108
2119
if (!ShouldDiagnoseUnusedDecl(D))
2109
2120
return;
2110
2121
@@ -2126,10 +2137,11 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
2126
2137
else
2127
2138
DiagID = diag::warn_unused_variable;
2128
2139
2129
- Diag (D->getLocation(), DiagID) << D << Hint;
2140
+ DiagReceiver (D->getLocation(), PDiag( DiagID) << D << Hint) ;
2130
2141
}
2131
2142
2132
- void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
2143
+ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD,
2144
+ DiagReceiverTy DiagReceiver) {
2133
2145
// If it's not referenced, it can't be set. If it has the Cleanup attribute,
2134
2146
// it's not really unused.
2135
2147
if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr<UnusedAttr>() ||
@@ -2175,10 +2187,11 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
2175
2187
return;
2176
2188
unsigned DiagID = isa<ParmVarDecl>(VD) ? diag::warn_unused_but_set_parameter
2177
2189
: diag::warn_unused_but_set_variable;
2178
- Diag (VD->getLocation(), DiagID) << VD;
2190
+ DiagReceiver (VD->getLocation(), PDiag( DiagID) << VD) ;
2179
2191
}
2180
2192
2181
- static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
2193
+ static void CheckPoppedLabel(LabelDecl *L, Sema &S,
2194
+ Sema::DiagReceiverTy DiagReceiver) {
2182
2195
// Verify that we have no forward references left. If so, there was a goto
2183
2196
// or address of a label taken, but no definition of it. Label fwd
2184
2197
// definitions are indicated with a null substmt which is also not a resolved
@@ -2189,7 +2202,8 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
2189
2202
else
2190
2203
Diagnose = L->getStmt() == nullptr;
2191
2204
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);
2193
2207
}
2194
2208
2195
2209
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
@@ -2199,6 +2213,24 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
2199
2213
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
2200
2214
"Scope shouldn't contain decls!");
2201
2215
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
+
2202
2234
for (auto *TmpD : S->decls()) {
2203
2235
assert(TmpD && "This decl didn't get pushed??");
2204
2236
@@ -2207,11 +2239,11 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
2207
2239
2208
2240
// Diagnose unused variables in this scope.
2209
2241
if (!S->hasUnrecoverableErrorOccurred()) {
2210
- DiagnoseUnusedDecl(D);
2242
+ DiagnoseUnusedDecl(D, addDiag );
2211
2243
if (const auto *RD = dyn_cast<RecordDecl>(D))
2212
- DiagnoseUnusedNestedTypedefs(RD);
2244
+ DiagnoseUnusedNestedTypedefs(RD, addDiag );
2213
2245
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
2214
- DiagnoseUnusedButSetDecl(VD);
2246
+ DiagnoseUnusedButSetDecl(VD, addDiag );
2215
2247
RefsMinusAssignments.erase(VD);
2216
2248
}
2217
2249
}
@@ -2220,21 +2252,35 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
2220
2252
2221
2253
// If this was a forward reference to a label, verify it was defined.
2222
2254
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
2223
- CheckPoppedLabel(LD, *this);
2255
+ CheckPoppedLabel(LD, *this, addDiag );
2224
2256
2225
2257
// Remove this name from our lexical scope, and warn on it if we haven't
2226
2258
// already.
2227
2259
IdResolver.RemoveDecl(D);
2228
2260
auto ShadowI = ShadowingDecls.find(D);
2229
2261
if (ShadowI != ShadowingDecls.end()) {
2230
2262
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() );
2234
2266
}
2235
2267
ShadowingDecls.erase(ShadowI);
2236
2268
}
2237
2269
}
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
+ }
2238
2284
}
2239
2285
2240
2286
/// Look for an Objective-C class in the translation unit.
0 commit comments